реализация 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]