Это тонко.case
проверяет значение типа Either String (a, ParseState)
, поэтому при присвоении имени шаблону в
err@(Left _) -> err
err
этот же тип имеет.Однако возвращаемый тип функции говорит, что это должен быть Either String a
, который не соответствует типу err
Either String (a, ParseState)
.Глядя на тип Left
:
Left :: x -> Either x y
Когда вы используете Left
в правой части в
Left err -> Left err
Вы даете ему возможность выбрать другойy
, а именно a
вместо (a, ParseState)
.
Так что, хотя значения одинаковы, типы не совпадают, и поэтому они могутНе подставляйте.
Кстати, в вашем случае в Control.Arrow
есть несколько очень удобных функций (специализирующихся на (->)
для простоты):
left :: (a -> a') -> Either a b -> Either a' b
right :: (b -> b') -> Either a b -> Either a b'
(+++) :: (a -> a') -> (b -> b') -> Either a b -> Either a' b'
, семантика которыхфиксируются свободными теоремами (читай: они имеют только одну разумную реализацию, поэтому они делают то, что вы ожидаете от их типов).Таким образом, вы можете написать свой код как:
parse parser = right fst . runParse parser . ParseState