Проблема здесь связана с типами when
и either
, не относящимися к ContT:
when :: forall (m :: * -> *). (Monad m) => Bool -> m () -> m ()
either :: forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Второй аргумент должен иметь тип m ()
для некоторой монады m
. Таким образом, строка when
вашего кода может быть изменена следующим образом:
when True $ k (Left "Error message 2") >> return ()
для компиляции кода. Это, вероятно, не то, что вы хотите сделать, но оно дает нам подсказку о том, что может быть неправильным: тип k
был выведен как нечто неприятное для when
.
Теперь для подписи either
: обратите внимание, что два аргумента either
должны быть функциями, которые выдают результаты одного типа. Тип return
здесь определяется типом x
, который в свою очередь фиксируется явной подписью на v
. Таким образом, бит (k . Left)
должен иметь одинаковый тип; это в свою очередь исправляет тип k
at (определяется GHC)
k :: Either String () -> ContT (Either String ()) IO [String]
Это несовместимо с ожиданиями when
.
Однако, когда вы закомментируете строку x2
, ее влияние на представление кода в коде проверки типа исключается, поэтому k
больше не переводится в неудобный тип и может свободно принимать тип
k :: Either [Char] () -> ContT (Either [Char] ()) IO ()
, что хорошо в книге when
. Таким образом, код компилируется.
В качестве заключительного замечания я использовал средство контрольных точек GHCi для получения точных типов k
в двух сценариях - я далеко не настолько опытен, чтобы выписывать их вручную и быть в какой-либо степени уверен в их правильности , :-) Используйте :break ModuleName line-number column-number
, чтобы попробовать.