substitute':: (Eq a)=> a -> a -> [a] -> [a]
substitute' x y = map substituteOne
where
substituteOne x' | x == x' = y
| otherwise = x'
Итак, смысл этой функции в том, что она принимает два входа типа а и список типа а и заменяет все элементы в списке [а], происходящие из «первого» а, на «второй» а. По крайней мере, так написано в описании задачи.
Я уже реализовал рекурсивную версию, но также нужна функция с предложением where.
Так что это решение для него. Почему-то у меня вопросы:
При необходимости результат выглядит так:
substitute' 5 10 [1, 5, 2, 5, 3, 5]
[1,10,2,10,3,10]





substitute имеет тип a -> a -> [a] -> [a], что означает, что он принимает аргумент один и возвращает функцию типа a -> [a] -> [a]. Это связано с тем, что (->) является правоассоциативным, а приведенный выше тип эквивалентен a -> (a -> [a] -> [a]).
Поскольку приложение функции левоассоциативно, вызов типа substitute x y эквивалентен (substitute x) y; y — это аргумент функции, возвращаемый substitute x.
Когда кто-то пишет
substitute x y = ...
это синтаксический сахар для
substitute = \x -> \y -> ...
Кроме того, поскольку map substituteOne' имеет тип [a] -> [a], это делает его подходящим значением для возврата substitute x y.
substitute1 принимает параметр x'. Биты между символами | и = являются защитными условиями. Поскольку эта конкретная функция имеет только одно условие, вы можете переписать ее следующим образом:
substitute1 x' = if x == x' then y else x'
Поскольку это находится в предложении where, substitute1 также имеет доступ к параметрам x и y основной функции.
(1) how can
substituteOnein the second line work without any parameters?
(2) where do we give a list as input? or where do we state what we do with that list? I mean compiling and executing it works, but somehow I don’t see it
Параметры все еще там; это карри на работе. Рассмотрим часть инфиксного оператора(+1), который является частным случаем частичное применение. Получив число, он производит число, которое на единицу больше. Свидетель:
λ> :t (+1)
(+1) :: Num a => a -> a
Мы могли бы определить функцию для увеличения всех элементов списка, назвав список
λ> :t \l -> map (+1) l
\l -> map (+1) l :: Num b => [b] -> [b]
но это оказывается ненужным из-за карри.
λ> :t map (+1)
map (+1) :: Num b => [b] -> [b]
В конце концов, это программирование функциональный. С Haskell мы манипулируем функциями так же легко, как другие языки манипулируют строками.
(3) what is
x'? it is never defined anywhere, we just start working with it somehow (maybe refers also to question 1)
Но вы делать определяете x' как параметр substituteOne!
Рассмотрим тип map:
λ> :t map
map :: (a -> b) -> [a] -> [b]
Его первый аргумент является функцией одного параметра. Чтобы ваша программа выполняла проверку типов, типы должны выстроиться в линию. Мы можем подчеркнуть это для substituteOne, добавив необязательную аннотацию типа, но придется немного потрудиться (включив расширение переменные типа с областью действия), потому что substituteOne — это внутренняя функция со ссылками на внешние сфера,
substitute':: forall a. Eq a => a -> a -> [a] -> [a]
substitute' x y = map substituteOne
where
substituteOne :: a -> a
substituteOne x' | x == x' = y
| otherwise = x'
(4)
mapneeds a function and a list, so that it works. here we havemapfunction_. refers maybe to 2., but what would be the output ofsubstituteOne x'?
Использование безымянных аргументов в точке приложения, как в вашем коде с map substituteOne, известно как бесточечный стиль. В вашем случае есть две невидимые «точки» или имена переменных: аргумент на substituteOne и аргумент списка на map.
Вы можете быть откровенны обо всем, как в
substitute'' :: Eq a => a -> a -> [a] -> [a]
substitute'' x y l = map (\x' -> if x == x' then y else x') l
но это гораздо более загромождено по сравнению с ним.
Значения, выдаваемые substituteOne, собираются в списке, полученном с map.