Странно не может соответствовать тип ошибки
У меня есть простая однострочная функция:
revRange :: (Char,Char) -> [Char]
revRange t = unfoldr (\b -> if b == (pred (fst t)) then Nothing else Just (b, pred b)) (snd t)
Это работает хорошо:
*Main Data.List> revRange ('a', 'f')
"fedcba"
Затем я хочу извлечь Unoldr лямбда как уникальную функцию:
revRange :: (Char,Char) -> [Char]
revRange t = unfoldr fun t
fun t = (\b -> if b == (pred (fst t)) then Nothing else Just (b, pred b)) (snd t)
Теперь у меня странная ошибка:
Couldn't match type `Char' with `(Char, Char)'
Expected type: (Char, Char) -> Maybe (Char, (Char, Char))
Actual type: (Char, Char) -> Maybe (Char, Char)
In the first argument of `unfoldr', namely `fun'
In the expression: unfoldr fun t
1 ответ
Сначала отформатируйте код:
revRange :: (Char,Char) -> [Char]
revRange t = unfoldr fun t
fun t = (\b -> if b == (pred (fst t))
then Nothing
else Just (b, pred b)) (snd t)
Затем дважды проверьте тип unfoldr
с помощью Google:
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
Затем добавьте сигнатуру типа в fun
так что GHC скажет вам, в чем проблема. По типу unfoldr
, fun
должен иметь тип:
b ~ Char
a ~ Char
fun :: Char -> Maybe (Char, Char)
так как ты unfoldr
в исходном примере с snd t
,
Я обычно люблю проверять маленькие кусочки, чтобы мы могли убрать определение foo
и просто используйте сигнатуру типа:
revRange :: (Char,Char) -> [Char]
revRange t = unfoldr fun t
fun:: Char -> Maybe (Char, Char)
fun b = error ""
GHC жалуется, что t
имеет тип (Char, Char)
но fun
ожидает тип Char
, Ты звонил unfoldr fun t
вместо unfoldr fun (snd t)
как в оригинальном примере. Переместить этот бит из fun
в revRange
:
revRange :: (Char,Char) -> [Char]
revRange t = unfoldr fun (snd t)
fun:: Char -> Maybe (Char, Char)
fun b = error ""
Далее добавьте в определение fun
снова. Мы можем удалить лямбду и поставить b
как нормальный аргумент fun
:
fun:: Char -> Maybe (Char, Char)
fun t b = if b == (pred (fst t))
then Nothing
else Just (b, pred b)
Сразу же мы видим еще одну явную проблему: fun
принимает два аргумента, но в подписи написано, что он должен принимать только один!
поскольку t
является постоянной величиной в исходной лямбде, мы можем решить эту проблему, частично применяя fun
в revRange
итоговый ответ:
revRange :: (Char,Char) -> [Char]
revRange t = unfoldr (fun t) (snd t)
fun:: (Char, Char) -> Char -> Maybe (Char, Char)
fun t b = if b == (pred (fst t))
then Nothing
else Just (b, pred b)
Чтобы ответить на ваш комментарий, вы хотели бы написать
revRange :: (Char,Char) -> [Char]
revRange = unfoldr fun2
Используя тот же подход, что и выше, в подписи unfoldr
нам нужно b ~ (Char,Char)
а также a ~ Char
, Итак, мы хотели бы fun2
иметь тип
fun2 :: ((Char,Char) -> Maybe (Char, (Char, Char)))
Я оставлю определение fun2
в качестве упражнения. В качестве подсказки я предлагаю принять соглашение о том, что первая часть пары является постоянной и имеет место fst t
,