Извините, я не совсем следую вашей логике, но давайте посмотрим , что делает код без стрелки . Он
- Проверяет, является ли список пустым, если да, возвращает
- В противном случае отключает заголовок списка, вызывает элемент
x
- рекурсив в остальной части списка, вызов результата
ys
- Если предикат
p
истинен на голове, тогда мы добавляем x
к ys
.
- В противном случае мы возвращаем
ys
Функция listcase
[для реализации первых 2 задач] выглядит неплохо, хотя помните, что вы возвращаете список, поэтому с таким же успехом можете вернуть его вместо unit
и переназначить через const []
.
У вас есть код рекурсии для третьей пули, похороненный в двух последних случаях, тогда как я выставляю его напрямую, но это нормально.
Для последнего слияния вы пишете это с |||
, но, поскольку вам не нужно составлять какие-либо другие стрелки в вашей целевой категории, вы могли бы просто поднять функцию, чтобы выполнить всю работу. В моем коде ниже это rejoin
.
filterA :: forall arr a. ArrowChoice arr => arr a Bool -> arr [a] [a]
filterA p = arr lstcase >>> (filterRest ||| id) where
-- left if has a head, right otherwise
lstcase :: [a] -> (Either (a, [a]) [a])
lstcase (x:xs) = Left (x, xs)
lstcase [] = Right []
-- if we got a head, then
-- for the head ("first" in code), map this to itself and p's result on it
-- recurse on the rest of the list ("second" part)
-- append the element to the recursion result if p's result is true
filterRest :: arr (a, [a]) [a]
filterRest = (first (id &&& p) >>> second (filterA p) >>> arr rejoin)
rejoin :: ((a, Bool), [a]) -> [a]
rejoin ((x, True), rest) = x:rest
rejoin ((x, False), rest) = rest
Конечно, требуется время, чтобы четко выразить свои идеи с помощью ***
, &&&
, |||
, first
и т. Д.
Небольшая критика.
- Убедитесь, что вы реализуете функцию, которую они просят !! Если вы просто возьмете необработанную функцию
p
, то вы также можете объявить filterA = arr filter
. Вы действительно хотите взять поднятую стрелу p
. Тем не менее, изменение будет просто набирать p
вместо arr p
, так что ваш код имеет правильное представление.
(uncurry helper)
это не что-то в пространстве стрелок, это просто необработанная функция.
При разработке этого материала я обычно пишу скелет и объявляю типы. Это помогает мне понять, что происходит. Например, я начал с
filterA :: ArrowChoice arr => arr a Bool -> arr [a] [a]
filterA p = arr lstcase >>> (filterRest ||| id) where
-- left if has a head, right otherwise
lstcase :: [a] -> (Either (a, [a]) [a])
lstcase = undefined
filterRest :: arr (a, [a]) [a]
filterRest = undefined
Однако, когда вы добавляете fa
в объявление filterRest
, вы должны сказать ему, что arr
для filterRest
такое же, как для filterA
(тип переменной области видимости), поэтому используйте forall arr a.
как указано выше.