7

以下の標準のFunctorインスタンスを次に示しEither aます。

instance Functor (Either a) where
        fmap _ (Left x) = Left x
        fmap f (Right y) = Right (f y)

as-patternを追加すると、GHCiにロードするときにコンパイルエラーが発生します。

instance Functor (Either a) where
        fmap _ z@(Left x) = z          -- <-- here's the as-pattern
        fmap f (Right y) = Right (f y)

Couldn't match expected type `b' against inferred type `a1'
  `b' is a rigid type variable bound by
      the type signature for `fmap' at <no location info>
  `a1' is a rigid type variable bound by
       the type signature for `fmap' at <no location info>
  Expected type: Either a b
  Inferred type: Either a a1
In the expression: z
In the definition of `fmap': fmap _ (z@(Left x)) = z

なぜこれが機能しないのですか?

4

4 に答える 4

11

fmap署名があります(a -> b) -> f a -> f b。つまり、異なることを許可する必要がaありbます。実装では、引数として渡されたものab同じものを返すため、同じにすることしかできません。だからGHCは文句を言う。

于 2012-08-21T13:57:30.457 に答える
2

私の最善の推測はz、方程式の両側で異なる型を表すため、これが失敗することです。

  • 全体的なタイプはfmap :: (a -> b) -> Either t a -> Either t b

  • 左側に、z :: Either t a

  • 右側に、z :: Either t b

Left x同じ方程式に複数の異なる型を含めることが許可されているようですが、そうではzありません。

この実装も、明らかに同じ理由で失敗します。

instance Functor (Either a) where
        fmap f (Right y) = Right (f y)
        fmap _ z = z          

Couldn't match expected type `b' against inferred type `a1'
  `b' is a rigid type variable bound by
      the type signature for `fmap' at <no location info>
  `a1' is a rigid type variable bound by
       the type signature for `fmap' at <no location info>
  Expected type: Either a b
  Inferred type: Either a a1
In the expression: z
In the definition of `fmap': fmap _ z = z
于 2012-08-21T13:58:29.097 に答える
2

fmaptoの署名を特殊化するとEither l、次のようになります。

fmap :: (a -> b) -> Either l a -> Either l b

これはLeft r、 case ステートメントの左側でパターン マッチングする が type でなければならないことを意味しますEither l a。ただし、 を返却する必要があるため、そのまま返却することはできませんEither l b。これには、左側の値を new で再ラップする必要があります。これにより、コンパイラは、値の型が異なる可能性Leftのある新しく作成された を返していると推測できます。EitherRight

于 2012-08-21T19:24:00.260 に答える
2

Either aインスタンスの場合、fmap次のタイプがあります。

(i -> j) -> Either a i -> Either a j

この方程式では:

fmap _ (Left x) = Left x

2 番目の引数は型Either a iであり、 pattern に一致することがわかっていますLeft x。を取り出しx、それに適用Leftして の結果を取得しfmapます。

秘訣はLeft、方程式の左辺が右辺と同じではないということLeftです! LHSLeftには、次のコンストラクターがあります。

Left :: a -> Either a i

RHS では、Leftこのコンストラクターは次のようになります。

Left :: a -> Either a j

パターンで使用されるRHSはの 2 番目の引数のLeft型と一致せず、LHSはの結果として必要な型の値を構築しません。fmapEither a iLeftfmapEither a j

したがってLeft、意味的に言えば、両方に同じものを使用する方法はありません。で見つかったLeft x :: Either a jを含む新しいを作成する必要があります。運用上、Haskell の実装は、これら 2 つの項を同じように表現する場合としない場合があり、異なる型を持つ 2 つの値の単一のメモリ内表現を共有できる場合とできない場合があり、構造を最適化するのに十分賢い場合とそうでない場合があります。すでに手元にある別の値と同じように表される新しい値の。しかし、これらの実装の問題はプログラムの意味とは異なり、型チェッカーの役割は純粋に意味に関係しています。xLeft x :: Either a i

于 2012-08-22T01:52:20.107 に答える