2012-05-06 4 views
5

Я относительно новичок в Haskell, так что извиняюсь, если мой вопрос звучит глупо. Я пытался понять, как работает композиция функций, и я столкнулся с проблемой, о которой мне было интересно, кто-то может мне помочь. Я использую карту в функции композиции в двух следующих случаях:Haskell: Использование карты в функциональной композиции

  • map (*2) . filter even [1,2,3,4]
  • map (*2) . zipWith max [1,2] [4,5]

Хотя обе функции zipWith фильтр и возвращает список, только первая композиция работает, а второй в результате чего возникает ошибка ниже:

"Couldn't match expected type '[Int] -> [Int]' with actual type '[c0]' 

Любые предложения были бы весьма полезными.

+1

Ответы на [этот вопрос] (http://stackoverflow.com/questions/2834626/haskell-dot-operator) помогают? (Особенно [этот] (http://stackoverflow.com/a/2834661/1256624)) – huon

+1

Первый фактически производит вывод 'Не может соответствовать ожидаемому типу a0 -> [b0] 'с фактическим типом [a1] ' –

ответ

5

Результат zipWith max [1,2] [4,5] - это список, а не функция. Оператор (.) Требует функции в качестве своего правого операнда. Отсюда ошибка на второй строке. Вероятно, вы хотите, чтобы

map (*2) (zipWith max [1,2] [4,5]) 

Ваш первый пример не компилируется на WinHugs (Hugs mode); он имеет ту же ошибку. Ниже приводится описание работы

(map (*2) . filter even) [1,2,3,4] 

как он состоит из двух функций и применяет полученную функцию к аргументу.

16

Напомним тип (.).

(.) :: (b -> c) -> (a -> b) -> a -> c 

Он принимает три аргумента: две функции и начальное значение, и возвращает результат двух функций состоит.

Теперь применение функции к ее аргументам становится более строгим, чем оператор (.). Так ваше выражение:

map (*2) . filter even [1,2,3,4] 

обрабатывается как:

(.) (map (*2)) (filter even [1,2,3,4]) 

сейчас, первый аргумент, map (*2) нормально. Он имеет тип (b -> c), где b и c - Num a => [a]. Тем не менее, второй аргумент один список:

Prelude> :t filter even [1,2,3,4] 
filter even [1,2,3,4] :: Integral a => [a] 

и поэтому тип проверки будет жаловаться, что вы передаете [a] в качестве аргумента, когда функция (.) нуждается в функции.

И вот что мы видим:

Couldn't match expected type `a0 -> [b0]' with actual type `[a1]' 
In the return type of a call of `filter' 
In the second argument of `(.)', namely `filter even [1, 2, 3, 4]' 
In the expression: map (* 2) . filter even [1, 2, 3, 4] 

Итак ... скобок!

Либо использовать оператор $ добавить скобку:

map (*2) . filter even $ [1,2,3,4] 

или использовать явные скобки, удаление композиции из двух функций

map (*2) (filter even [1,2,3,4]) 

или даже:

(map (*2) . filter even) [1,2,3,4] 
+0

спасибо Дону. это было действительно полезно – wajeeh

+1

Если бы это было полезно, вы должны принять ответ Дона. – augustss

+1

Я знаю, что ОП задал вопрос о композиции функций, но этот пример действительно лучше всего подходит для прямого '$', _i.e._, 'map (* 2) $ filter even [1,2,3,4]' , – apc

4

The следующие формы:

map (* 2) $ filter even [1, 2, 3, 4] 
(map (* 2) . filter even) [1, 2, 3, 4] 
map (* 2) $ zipWith max [1, 2] [4, 5] 
(\xs -> map (* 2) . zipWith max xs) [1, 2] [4, 5] 

но не следующее:

map (* 2) . filter even [1, 2, 3, 4] 
map (* 2) . zipWith max [1, 2] [4, 5] 
(map (* 2) . zipWith max) [1, 2] [4, 5] 

Почему это так? Ну, возьмем, к примеру

map (* 2) . zipWith max [1, 2] [4, 5] 

это то же самое, как

(map (* 2)) . (((zipWith max) [1, 2]) [4, 5]) 

(map (* 2)) имеет тип [Int] -> [Int] (предполагается, что недобросовестный для Int), (((zipWith max) [1, 2]) [4, 5]) имеет тип [Int] и (.) имеет тип (b -> c) -> (a -> b) -> a -> c или ([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int] в этом Непро- полиморфный случай, так что это плохо напечатано. С другой стороны ($) имеет тип (a -> b) -> a -> b или ([Int] -> [Int]) -> [Int] -> [Int] в этом без полиморфного случае, так это:

(map (* 2)) $ (((zipWith max) [1, 2]) [4, 5]) 

хорошо напечатал.

2

Благодаря низкому старшинства (.), Haskell разбирает

map (*2) . filter even [1,2,3,4] 

в

map (*2) . (filter even [1,2,3,4]) 

т.е. составляют map (*2) (функции) с результатом filter even [1,2,3,4] (список), который не имеет никакого смысла , и это ошибка типа.

Вы можете исправить это с помощью @ предложения Теодора, или с помощью ($):

map (*2) . filter even $ [1,2,3,4] 
2

Если проверить тип карты это: (a -> b) -> [a] -> [b]

Таким образом, он принимает функцию А в В а затем список a и возвращает список b. Правильно?

Теперь вы уже предоставляете функцию a в b, передавая параметр (*2). Таким образом, ваша частично примененная функция отображения в конечном итоге составляет: [Integer] -> [Integer], что означает, что вы получите список целых чисел и верните список целых чисел.

До этого момента вы могли бы составить (.) Функцию, имеющую ту же подпись. Если вы проверите тип filter even, вы увидите, что это: [Integer] -> [Integer], как настоящий действительный кандидат на композицию здесь.

Этот состав затем, не меняет окончательную сигнатуры функции, если проверить тип: map (*2) . filter even это [Integer] -> [Integer]

Это не было бы в случае с map (*2) . zipWith max [1,2] [4,5], потому что zipWith max не то же самое подпись, как ожидается от map (*2).

+0

спасибо. Все это имеет смысл сейчас – wajeeh

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