2015-03-30 1 views
1

У меня есть простая функция одна строки:Weird не может соответствовать ошибке типа

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" 

Тогда я хочу, чтобы извлечь unfoldr лямбды, как уникальная функция:

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 
+0

Похоже, что вы включили 'snd t', который является вторым аргументом' unfoldr' в исходной версии, в 'fun', который должен быть только лямбда-выражением? – kosmikus

ответ

7

Во-первых, формат кода:

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 с помощью Hoogle:

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.

+0

спасибо за такой полный ответ. – David

+0

У меня есть еще один вопрос. Можно ли переместить '(snd t)' в 'fun'? Я хочу видеть первую строку как 'revRange = unfoldr'. – David

+0

@David см. Обновленный ответ – crockeea

 Смежные вопросы

  • Нет связанных вопросов^_^