22

私は Haskell の初心者なので、答えが明らかである場合は申し訳ありませんが、カテゴリをよりよく理解するために Typeclassopedia に取り組んでいます。ファンクターのセクションの演習を行っているときに、次の問題に遭遇しました。

Functor のインスタンスにできない種類の * -> * の型の例を挙げてください (undefined を使用しないと)。

私が最初に考えたのは、ある種の無限再帰的な fmap の定義を定義することでしたが、それはundefined定義で使用されている場合と本質的に同じではないでしょうか?

誰かが答えを説明できれば、それは大歓迎です。

ありがとう!

元の演習のソース、セクション 3: http://www.haskell.org/haskellwiki/Typeclassopedia#Introduction

4

3 に答える 3

23

簡単な例は

data K a = K (a -> Int)

Functorのインスタンスを自動的に派生させようとすることを ghci が教えてくれるのは次のKとおりです。

Prelude> :set -XDeriveFunctor
Prelude> data K a = K (a -> Int)
Prelude> :k K
K :: * -> *
Prelude> data K a = K (a -> Int) deriving Functor

<interactive>:14:34:
    Can't make a derived instance of `Functor K':
      Constructor `K' must not use the type variable in a function argument
    In the data type declaration for `K'

問題は、標準Functorクラスが実際に共変ファンクターを表す (fmap引数を に持ち上げる) ことですが、型の関数を作成して取得f a -> f bする方法がないことです(Ramon の回答を参照)。ただし、反変ファンクターの型クラスを定義することは可能です。a -> ba -> Intb -> Int

class Contravariant f where
    contramap :: (a -> b) -> f b -> f a 

Kそのインスタンスを作成します。

instance Contravariant K where
    contramap f (K g) = K (g . f)

Haskell の共分散/反分散の詳細については、こちらを参照してください。

編集: Reddit の Chris Smith からのこのトピックに関する素敵なコメントもあります。

于 2013-04-20T09:01:07.390 に答える
6

私の(短い)コメントとミハイルの答えを拡張するには:

を考えると(-> Int)、次のようになると予想fmapされます。

(a -> Int) -> (a -> b) -> (b -> Int)

また:

(a -> Int) -> (a -> b) -> b -> Int

(a -> Int)3 つの引数から( なしで(a -> b))bに到達する方法がないことを証明するのは簡単です。したがって、 からに到達する方法はありません。結論: のインスタンスは存在しません。Intundefined(a -> Int)(a -> b)(b -> Int)Functor(-> Int)

于 2013-04-20T09:07:30.873 に答える
0

これにも問題があり、ラモンとミハイルの回答が有益であることがわかりました-ありがとう! 500 文字では短すぎるため、またコードの書式設定のために、これをコメントではなく回答に入れています。

私は何が共変であるかを理解するのに苦労していました.Functorのインスタンスにすることができる(a -> Int)この反例を思いつきました(Ramonの証明を反証します)data K a = K (a -> Int)

data K a = K (a -> Int)
instance Functor K where
  fmap g (K f) = K (const 0)

コンパイルできれば、それは正しいはずですよね? ;-) 他の順列を試すのに時間を費やしました。関数をフロップするだけで簡単になりました。

-- "o" for "output"
-- The fmapped (1st) type is a function output so we're OK.
data K0 o = K0 (Int -> o)
instance Functor K0 where
  fmap :: (oa -> ob) -> (K0 oa) -> (K0 ob)
  fmap g (K0 f) = K0 (g . f)

Int を型変数に変換すると、セクション 3.2 演習 1 パート 2 になりました。

-- The fmapped (2nd) type argument is an output
data K1 a b = K1 (a -> b)
instance Functor (K1 a) where
  fmap :: (b1 -> b2) -> K1 a b1 -> K1 a b2
  fmap g (K1 f) = K1 (g . f)

fmapped型を関数の引数にすることが鍵でした...ミハイルの答えが言ったように、今ではそれを理解しています;-)

-- The fmapped (2nd) type argument is an input
data K2 a b = K2 (b -> a) 
instance Functor (K2 o) where
  fmap :: (ia -> ib) -> (K2 o ia) -> (K2 o ib)
  -- Can't get our hands on a value of type o
  fmap g (K2 f) = K2 (const (undefined :: o))
  -- Nor one of type ia
  fmap g (K2 f) = K2 (const (f (undefined :: ia)))
于 2018-10-20T01:59:22.637 に答える