Странно не может соответствовать тип ошибки

У меня есть простая однострочная функция:

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,

Другие вопросы по тегам