import Control.Applicative
main = print $ fmap (*2) (1,2)
(1,4)
を生成します。 (2,4)
を生成することを期待しますが、代わりに関数はタプルの2番目の要素にのみ適用されます。
更新私は基本的にこれをほぼすぐに理解しました。すぐに自分の答えを投稿します。
Functor
インスタンスは、実際にはControl.Applicative
によってインポートされた GHC.Base モジュールからのものです。
必要なインスタンスを作成しようとすると、タプルの定義を考えると、機能しないことがわかります。インスタンスに必要なタイプパラメータは1つだけですが、2タプルには2つあります。
有効なFunctor
インスタンスは、少なくとも各要素に同じタイプのタプル(a,a)
上にある必要がありますが、インスタンスを次のように定義するなど、卑劣なことはできません。
type T2 a = (a,a)
インスタンスタイプを同義語にすることは許可されていないためです。
上記の制限された2タプルの同義語は、論理的には次のタイプと同じです。
data T2 a = T2 a a
どのcanがFunctorインスタンスを持つことができます:
instance Functor T2 where
fmap f (T2 x y) = T2 (f x) (f y)
Gabrielがコメントで述べたように、これは構造の分岐や並行性に役立つ可能性があります。
質問でこれに答えさせてください:あなたはどの出力を期待しますか:
main = print $ fmap (*2) ("funny",2)
あなたcanあなたが望むものを持っています(data Pair a = Pair a a
などを使用)が、(,)
は最初と2番目の引数で異なるタイプを持っているかもしれないので、あなたは運が悪いです。
ペアは、基本的に次のように定義されます。
_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つの便利なクラスは、_Data.Bifunctor
_の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
インスタンスを使用してペアを直接操作することもできます。