реализация foreach для начинающих / учащихся в haskell

Я пытаюсь реализовать морфизм foreach, чтобы проверить свое понимание определения морфизма и сопоставления шаблонов... Очевидно, я полностью упускаю оба момента.

не могли бы вы меня поправить ? Я хочу морфизм foreach в список a и морфизм f в качестве аргументов и возвращает список результатов r of f применить ко всем a элементы.

foreach :: [a] → f → [r]
foreach [] f = []
foreach x:[] f = (f x):[]
foreach []:x f = []:(f x)
foreach (x:xs) f = (f x) : (foreach (xs f))

при компиляции, у меня есть srcMain.hs:23:0: Parse error in pattern

3 ответов


проблема синтаксическая, в этой строке:

foreach x:[] f = (f x):[]

приложение конструктора в шаблонах обычно должно быть заключено в скобки. Это сработает:

foreach (x:[]) f = (f x):[]

кстати... применение функции имеет наивысший приоритет, поэтому, с другой стороны, вам не нужны круглые скобки с правой стороны:

foreach (x:[]) f = f x:[]

вышеизложенное справедливо для любого конструктора infix, но в качестве заключительного примечания для списков, в частности, есть специальный синтаксис:

foreach [x] f = [f x]

есть и другие проблемы с вашим кодом, как он стоит, но это ошибка. Краткий обзор других проблем:

foreach :: [a] → f → [r]

переменные типа неявно универсально квантифицированы, поэтому это означает любой тип f. Вам нужен более конкретный тип, а именно a -> r.

foreach x:[] f = (f x):[]

это не нужно--рекурсивный случай будет работать правильно здесь, применяя f to x и вызывая себя на хвост, дающий пустой список кейсов.

foreach []:x f = []:(f x)

я не думаю, что это означает то, что вы думаете, что это означает-это шаблон, соответствующий главе списка против пустого списка [], подразумевая, что функция работает над списком списков.

foreach (x:xs) f = (f x) : (foreach (xs f))

скобки здесь либо ненужные, либо неправильные. Опять же, приложение функции имеет более высокий приоритет, чем такие операторы, как :. Кроме того, (xs f) средств применения xs to f, как будто это был функция. Применить foreach для двух аргументов, просто foreach xs f хватит.


для сравнения, вот исходный код для (идентичной, за исключением порядка аргументов) стандартной библиотечной функции map:

map :: (a -> b) -> [a] -> [b]
map _ []     = []
map f (x:xs) = f x : map f xs

подпись типа, которую вы даете, является (по крайней мере, по мнению компилятора Haskell) фиктивной. Это функция, которая принимает список элементов любого a и любой тип f, и производит список значений любой тип r. Это как сказать "у меня есть куча слонов и отвертка. Превратите каждого слона в манго".

кажется, ваша цель-реализовать map функция:

map :: (a -> b) -> [a] -> [b]

конечно, это совершенно справедливо, чтобы перевернуть аргументы:

foreach :: [a] -> (a -> b) -> [b]

ваша реализация довольно близка, но есть несколько проблем.

самое большое, чтобы иметь в виду, что вы работаете с списки, а не массивы. The : оператор, также известный как "минусы", берет элемент и добавляет его в список (например,1 : [2,3,4]). Вы не можете использовать его для произвольного объединения элементов и списков, как в []:(f x). Есть ++ оператор который объединяет два списка (например,[f x] ++ xs, что то же самое, что (f x) : xs), но вам это не нужно для реализации foreach.

и наконец, (foreach (xs f)) не делает то, что вы можете подумать, что он делает. Это не так foreach(xs,f) на языке C-стиля это похоже на foreach(xs(f)). (xs f), само по себе, как с помощью xs как функция и применение f в качестве аргумента. Вместо этого, вы хотите (foreach xs f).

я остановлюсь здесь, чтобы не дать слишком много. Одна маленькая фишка хотя: применение функции имеет более высокий приоритет, чем любой оператор, поэтому вместо (f x) : (foreach xs f), вы можете сказать f x : foreach xs f.


вы забыли поставить () на foreach []:x f = []:(f x) и неправильно указан тип функции, теперь необходимо скомпилировать следующее:

foreach :: [a] -> (a -> r) -> [r]
foreach [] f = []
foreach (x:[]) f = (f x):[]
foreach (x:xs) f = (f x) : (foreach xs f)

и

*Main> foreach [1..20] (+1)
[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21]