Не может быть сделано.
Сгиб влево обязательно расходится в бесконечных списках, а take n
- нет. Это так, потому что левый сгиб хвостовой рекурсии, поэтому он должен просмотреть весь список ввода, прежде чем он сможет начать обработку.
При правильном сгибе это
ntake :: Int -> [a] -> [a]
ntake 0 _ = []
ntake n xs = foldr g z xs 0
where
g x r i | i>=n = []
| otherwise = x : r (i+1)
z _ = []
ndrop :: Int -> [a] -> [a]
ndrop 0 xs = xs
ndrop n xs = foldr g z xs 0 xs
where
g x r i xs@(_:t) | i>=n = xs
| otherwise = r (i+1) t
z _ _ = []
ndrop
реализует параморфизм красиво и верно, вплоть до порядка аргументов функции-редуктора g
, предоставляя ему доступ как к текущему элементу x
, так и к текущему узлу списка xs
(такой, что xs == (x:t)
), а также рекурсивный результат r
. Редуктор катаморфизма имеет доступ только к x
и r
.
Сгибы обычно кодируют катаморфизмы, но это показывает, что правильное сгибание может также использоваться для кодирования параморфизма. Это универсально таким образом. Я думаю, что это красиво.
Что касается ошибки типа, чтобы исправить ее, просто переключите аргументы на func
:
func y x | ..... = .......
Аккумулятор в левом сгибе является аргументом first для функции-редуктора.
Если вы действительно хотите сделать это с левой складкой, и если вы действительно уверены, что списки конечны, два варианта:
ltake n xs = post $ foldl' g (0,id) xs
where
g (i,f) x | i < n = (i+1, f . (x:))
| otherwise = (i,f)
post (_,f) = f []
rltake n xs = foldl' g id xs r n
where
g acc x = acc . f x
f x r i | i > 0 = x : r (i-1)
| otherwise = []
r _ = []
Первое считается слева направо вверх, потенциально останавливая сборку префикса в середине обхода полного списка, который он, тем не менее, переносит до конца, будучи левым сгибом.
Второй также полностью пересекает список, превращая его в правый сгиб, который , а затем снова начинает работать с обратным отсчетом слева и может фактически перестать работать, как только префикс собран.
Реализация drop
таким образом неизбежно будет (?) Еще более громоздкой. Может быть хорошим упражнением.