import Control.Applicative
main = print $ fmap (*2) (1,2)
を生成し(1,4)
ます。生成されると思い(2,4)
ますが、代わりに関数はタプルの2番目の要素にのみ適用されます。
更新私は基本的にこれをほぼすぐに理解しました。すぐに自分の答えを投稿します。
質問でこれに答えさせてください:あなたはどの出力を期待しますか:
main = print $ fmap (*2) ("funny",2)
好きなように(使用するなどして)何かを持つことができますが、最初と2番目の引数に異なるタイプがある可能性があるため、運が悪いです。data Pair a = Pair a a
(,)
ペアは、基本的に次のように定義されます。
data (,) a b = (,) a b
クラスは次のFunctor
ようになります。
class Functor f where
fmap :: (a -> b) -> f a -> f b
関数の引数と結果の型は種類を持っている必要があるため*
(つまり、さらにエキゾチックなものに適用できる型関数ではなく値を表す)、、、、そして最も重要な目的のために、をa :: *
持っている必要があります。種類があるので、に適した型を取得するには、種類の種類に適用する必要があります。したがってb :: *
f :: * -> *
(,)
* -> * -> *
*
Functor
instance Functor ((,) x) where
-- fmap :: (a -> b) -> (x,a) -> (x,b)
したがって、実際には、他のことをFunctor
行うインスタンスを作成する方法はありません。
ペアを操作するためのより多くの方法を提供する1つの便利なクラスはBifunctor
、からData.Bifunctor
です。
class Bifunctor f where
bimap :: (a -> b) -> (c -> d) -> f a c -> f b d
bimap f g = first f . second g
first :: (a -> b) -> f a y -> f b y
first f = bimap f id
second :: (c -> d) -> f x c -> f x d
second g = bimap id g
これにより、次のようなものを書くことができます(からData.Bifunctor.Join
):
newtype Join p a =
Join { runJoin :: p a a }
instance Bifunctor p => Functor (Join p) where
fmap f = Join . bimap f f . runJoin
Join (,)
その場合、は本質的にと同じPair
です。
data Pair a = Pair a a
もちろん、Bifunctor
インスタンスを使用してペアを直接操作することもできます。
Functor
インスタンスは、実際にはによってインポートされたGHC.BaseモジュールからのものControl.Applicative
です。
必要なインスタンスを作成しようとすると、タプルの定義を考えると、それが機能しないことがわかります。インスタンスに必要なタイプパラメータは1つだけですが、2タプルには2つあります。
有効なFunctor
インスタンスは、少なくとも(a,a)
各要素に対して同じタイプのタプル上にある必要がありますが、インスタンスを次のように定義するなど、卑劣なことはできません。
type T2 a = (a,a)
インスタンスタイプを同義語にすることは許可されていないためです。
上記の制限された2タプルの同義語は、論理的には次のタイプと同じです。
data T2 a = T2 a a
Functorインスタンスを持つことができます:
instance Functor T2 where
fmap f (T2 x y) = T2 (f x) (f y)
Gabrielがコメントで述べたように、これは構造の分岐や並行性に役立つ可能性があります。