Я предполагаю, что ошибка, которую вы получаете, заключается в попытке просто переключить foldr
на foldl'
:
myConcat xs ys = foldl' (:) ys xs
, что приводит к ошибке (используя мой реплик Hugs):
ERROR - Type error in application
*** Expression : foldl' (:) xs ys
*** Term : (:)
*** Type : a -> [a] -> [a]
*** Does not match : [a] -> a -> [a]
Обратите внимание на две последние строки (предоставленный тип и ожидаемый тип), что позиции [a]
и a
находятся в противоположных позициях.Это означает, что нам нужна функция, подобная (:)
, но принимающая аргументы в обратном порядке.
В Haskell есть функция, которая делает это для нас: функция flip
.По сути, flip
эквивалентно
flip :: (a -> b -> c) -> (b -> a -> c)
flip f y x = f x y
То есть flip
принимает двоичную функцию в качестве аргумента и возвращает другую двоичную функцию, аргументы которой обращены («перевернуты») от оригинала.Таким образом, хотя (:)
имеет тип a -> [a] -> [a]
, мы видим, что flip (:)
имеет тип [a] -> a -> [a]
, что делает его идеальным кандидатом в качестве параметра foldl'
.
Используя flip
, мытеперь имеем этот код:
myConcat xs ys = foldl' (flip (:)) ys xs
Это результат того факта, что foldl'
имеет тип (a -> b -> c) -> a -> [b] -> c
Запустив это с аргументами [1..5]
и [6..10]
, мы получимрезультат [5,4,3,2,1,6,7,8,9,10]
, что почти то, что мы хотим.Единственная проблема в том, что первый список в результате оказывается обратным.Добавление простого вызова к reverse
дает нам окончательное определение myConcat
:
myConcat xs ys = foldl' (flip (:)) ys (reverse xs)
Просмотр этого процесса показывает одну из приятных вещей, которая часто возникает при написании кода на Haskell: когдаВы сталкиваетесь с проблемой, вы можете решить ее один (маленький) шаг за раз.Это особенно верно, когда у вас уже есть одна работающая реализация, и вы просто пытаетесь написать другую.Важно отметить, что если вы измените одну часть реализации (в данном случае, изменив foldr
на foldl'
), то многие другие необходимые изменения просто выпадут из определений типов.Осталось лишь немного проблем исправления, которые можно легко найти, выполнив тестовые примеры или посмотрев на точную природу используемых функций.
PS: любые ребята из Haskell, которые могут освежить эту последнюю строкукод, не стесняйтесь делать это.Хотя это не ужасно, я не нахожу это очень симпатичным.К сожалению, я еще не так хорош с Haskell.