Функция приложения функции в Haskell

Допустим, у меня есть список функций

functions = [f, g, h]

каждый с типом a -> a

У меня также есть список значений, скажем, чисел, но здесь все должно работать.

vals = [1,2,3]

Я хочу применить каждую функцию в functions к соответствующему значению в vals

Мой первый инстинкт - использовать лямбда и zipWith как:

zipWith (\f v -> f v) functions vals

Но, честно говоря, это выглядит уродливо, и я не ожидал этого от такого прекрасного языка, как Haskell. Функция приложения функции звучит как решение. Что-то подобное существует? Я что-то упустил, и есть гораздо более приятное решение моей проблемы? На самом деле я написал эту конструкцию для решения Project Euler. Это работает, но мне это не нравится.


person Juan Pablo Santos    schedule 31.07.2013    source источник


Ответы (3)


zipWith ($) f v

$ — это приложение функции. Тот факт, что он имеет особенно низкий приоритет, иногда ставит людей в тупик.

person Thomas M. DuBuisson    schedule 31.07.2013

Достаточно странно,

zipWith id functions vals

тоже будет работать!

Но, на самом деле, zipWith ($) это правильный способ написать это.

person MtnViewMark    schedule 31.07.2013
comment
@JuanPablo Потому что $ на самом деле просто id, специализированный для работы только с функциями (с очень низким приоритетом и инфиксной нотацией). Тип $, учитывая, что он применяет функцию к аргументу, должен быть (a -> b) -> a -> b. Помня, что все функции Haskell на самом деле унарные (или, что то же самое, что -> ассоциируется справа), того же типа, что и (a -> b) -> (a -> b). Это означает, что он принимает функцию любого типа и дает вам функцию того же типа; просто частный случай id :: a -> a, который принимает значение любого типа и дает вам значение того же типа. - person Ben; 31.07.2013
comment
Другой способ взглянуть на это: использование zipWith id означает, что каждый результирующий элемент вычисляется id f v, а id f равно f, поэтому id f v равно f v. - person augustss; 31.07.2013

Вот еще один вариант, который может заставить вас немного подумать.

>>> import Control.Applicative
>>> let functions = ZipList [(+1), (*2), (*10)]
>>> let values    = ZipList [1, 2, 3]
>>> getZipList (functions <*> values)
[2, 4, 30]

ZipList — это просто оболочка для списка. В определении <*> для ZipList говорится: «Объедините список функций (слева) со списком аргументов (справа), применяя каждую функцию к аргументу по очереди».

Это отличается от определения <*> для обычного списка, в котором говорится: «Возьмите каждую возможную пару (функция, аргумент) из этих двух списков и примените функцию к аргументу».

person Chris Taylor    schedule 31.07.2013