41
import Control.Applicative

main = print $ fmap (*2) (1,2)

を生成し(1,4)ます。生成されると思い(2,4)ますが、代わりに関数はタプルの2番目の要素にのみ適用されます。

更新私は基本的にこれをほぼすぐに理解しました。すぐに自分の答えを投稿します。

4

3 に答える 3

31

質問でこれに答えさせてください:あなたはどの出力を期待しますか:

main = print $ fmap (*2) ("funny",2)

好きなように(使用するなどして)何かを持つことができますが、最初と2番目の引数に異なるタイプがある可能性があるため、運が悪いです。data Pair a = Pair a a(,)

于 2012-11-18T17:59:20.623 に答える
24

ペアは、基本的に次のように定義されます。

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インスタンスを使用してペアを直接操作することもできます。

于 2016-01-05T04:38:31.030 に答える
18

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がコメントで述べたように、これは構造の分岐や並行性に役立つ可能性があります。

于 2012-11-18T17:35:50.600 に答える