この回答では、コメントで行った提案の 1 つを少し拡張します。
f <$>
タプルに作用するときの型を見ることは可能ですか?
(<$>)
は多相関数です。
GHCi> :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
GHC 8 では、拡張機能を使用してTypeApplications
、型変数の一部またはすべてのインスタンス化を提供することにより、多相関数を特殊化できます (この場合、f
、 、a
およびがこのb
順序で提供されます)。
GHCi> :set -XTypeApplications
GHCi> :t (<$>) @Maybe
(<$>) @Maybe :: (a -> b) -> Maybe a -> Maybe b
GHCi> :t (<$>) @Maybe @Int
(<$>) @Maybe @Int :: (Int -> b) -> Maybe Int -> Maybe b
GHCi> :t (<$>) @Maybe @_ @Bool
(<$>) @Maybe @_ @Bool :: (t -> Bool) -> Maybe t -> Maybe Bool
GHCi> :t (<$>) @_ @Int @Bool
(<$>) @_ @Int @Bool
:: Functor t => (Int -> Bool) -> t Int -> t Bool
GHCi> :t (<$>) @Maybe @Int @Bool
(<$>) @Maybe @Int @Bool :: (Int -> Bool) -> Maybe Int -> Maybe Bool
ペアでそれを使用するには、ペア型コンストラクターのプレフィックス構文を使用します。
GHCi> :t (<$>) @((,) _)
(<$>) @((,) _) :: (a -> b) -> (t, a) -> (t, b)
GHCi> -- You can use the specialised function normally.
GHCi> -- That includes passing arguments to it.
GHCi> f x = x + 1
GHCi> :t (<$>) @((,) _) f
(<$>) @((,) _) f :: Num b => (t, b) -> (t, b)
_
inは、ペアの最初の要素 (型コンストラクター((,) _)
の最初の引数) の型を未指定のままにします。(,)
それを選択するたびに、異なるFunctor
. 必要に応じて、より具体的に指定できます。
GHCi> :t (<$>) @((,) String) f
(<$>) @((,) String) f :: Num b => (String, b) -> (String, b)
最後に、3 タプルでこれを試してみるとどうなるか見てみる価値があります。
GHCi> :t (<$>) @((,,) _ _) f
(<$>) @((,,) _ _) f
:: (Num b, Functor ((,,) t t1)) => (t, t1, b) -> (t, t1, b)
Daniel Wagner がanswer で説明しているように、baseFunctor
は3 タプルのインスタンスを定義しません。それにもかかわらず、型チェッカーは、どこかで誰かが最初の 2 つの型パラメーターの選択に固有のインスタンスを定義した可能性を排除することはできませんが、それは無意味です。そのため、投機的制約が型に現れます ( baseにインスタンスFunctor ((,,) t t1)
があるため、ペアではそのようなことは起こりません)。予想通り、最初の 2 つの型パラメーターをインスタンス化しようとするとすぐに爆発します。Functor ((,) a)
GHCi> :t (<$>) @((,,) Bool String) f
<interactive>:1:1: error:
• Could not deduce (Functor ((,,) Bool String))
arising from a use of ‘<$>’
from the context: Num b
bound by the inferred type of
it :: Num b => (Bool, String, b) -> (Bool, String, b)
at <interactive>:1:1
• In the expression: (<$>) @((,,) Bool String) f