Почему этот код Either-monad не проверяет тип? - PullRequest
5 голосов
/ 06 апреля 2010
instance Monad (Either a) where
     return = Left
     fail = Right
     Left x >>= f = f x
     Right x >>= _ = Right x

этот фрагмент кода в 'baby.hs' вызвал ужасную ошибку компиляции:

Prelude> :l baby
[1 of 1] Compiling Main             ( baby.hs, interpreted )

baby.hs:2:18:
Couldn't match expected type `a1' against inferred type `a'
  `a1' is a rigid type variable bound by
       the type signature for `return' at <no location info>
  `a' is a rigid type variable bound by
      the instance declaration at baby.hs:1:23
In the expression: Left
In the definition of `return': return = Left
In the instance declaration for `Monad (Either a)'

baby.hs:3:16:
Couldn't match expected type `[Char]' against inferred type `a1'
  `a1' is a rigid type variable bound by
       the type signature for `fail' at <no location info>
  Expected type: String
  Inferred type: a1
In the expression: Right
In the definition of `fail': fail = Right

baby.hs:4:26:
Couldn't match expected type `a1' against inferred type `a'
  `a1' is a rigid type variable bound by
       the type signature for `>>=' at <no location info>
  `a' is a rigid type variable bound by
      the instance declaration at baby.hs:1:23
In the first argument of `f', namely `x'
In the expression: f x
In the definition of `>>=': Left x >>= f = f x

baby.hs:5:31:
Couldn't match expected type `b' against inferred type `a'
  `b' is a rigid type variable bound by
      the type signature for `>>=' at <no location info>
  `a' is a rigid type variable bound by
      the instance declaration at baby.hs:1:23
In the first argument of `Right', namely `x'
In the expression: Right x
In the definition of `>>=': Right x >>= _ = Right x
Failed, modules loaded: none.

почему это случилось? и как я могу сделать этот код скомпилировать? спасибо за любую помощь ~

Понятно. и я изменил код, чтобы увидеть, что он компилируется:

instance Monad (Either a) where
     return = Right
     Left a >>= f = Left a
     Right x >>= f = f x

успешно компилируется! но ... для дальнейшего вопроса:

instance Monad (Either a)

делает 'Либо' монадой, и я получил 'return = Right' ... как я могу получить 'return = Left'? я пробовал это, но не смог:

instance Monad (`Either` a) where
     return = Left
     Right a >>= f = Right a
     Left x >>= f = f x

или: Экземпляр Monad (\ x -> Либо x a)

не компилируется вообще!

Ответы [ 2 ]

9 голосов
/ 06 апреля 2010

Большая часть путаницы проистекает из того факта, что левый и правый используются в обратном направлении. Учитывая только тип для возврата, его тип из класса типов Monad выглядит следующим образом:

return :: (Monad m) => b -> m b

Вы пытаетесь определить экземпляр для m = Either a, поэтому return должен иметь тип:

return :: b -> Either a b

Вы определяете его как Левый, который имеет тип:

Left :: a -> Either a b

Обратите внимание, как отличается левая сторона ->.

3 голосов
/ 06 апреля 2010
  1. return должен иметь тип forall b. b -> Either a b, однако Left имеет тип forall c. a -> Either a c.Вы, вероятно, хотите прямо здесь.
  2. fail должен иметь тип forall b. String -> Either a b, однако Right имеет тип forall b. b -> Either a b, так что если b=String, то это означает String -> Either a String, что не подходит.*>>= должен иметь тип Either a b -> (b -> Either a c) -> Either a c, однако Right x >>= _ = Right x всегда возвращает значение типа Either a b, а не Either a c.
  3. Left x >>= f = f x не работает, поскольку x имеет тип a, ноf имеет тип b -> c.
...