Я пытаюсь создать относительно простую функцию, которая почти совмещает, но с небольшим поворотом. Предполагается, что последний и первый элементы каждого списка двоично или вместе и объединяются в процессе. Я' Я работаю над тем, чтобы научиться писать код, который может использовать возможности Stream Fusion в Data.List.Stream
Я проверил, что concat в базе выполняет то, что необходимо, и лениво строит список, однако эта версия, которую я создал, не работает. т. в базе concat задается следующим образом:
concat :: [[a]] -> [a]
concat = foldr (++) []
(++) :: [a] -> [a] -> [a]
(++) [] ys = ys
(++) (x:xs) ys = x : xs ++ ys
Вот мой код:
bconcat :: [[Word8]] -> [Word8]
bconcat = foldr1 bappend
bappend :: [Word8] -> [Word8] -> [Word8]
bappend as bs = init as ++ (last as .|. head bs) : tail bs
У меня возникает вопрос: как мне написать это, чтобы список строился лениво? Я даже попытался написать bappend, имитируя определение (++) в базе, но это не имело значения.
На данный момент я использую следующий код, он работает так, как я хочу, но производительность отстает от concat. Кроме того, он использует явную рекурсию, которой я бы хотел избежать.
bconcat :: [[Word8]] -> [Word8]
bconcat (a:b:xs) = init a ++ bconcat ((bappend (last a) b):xs)
bconcat (a:[]) = a
bconcat [] = []
bappend :: Word8 -> [Word8] -> [Word8]
bappend !a bs = (a .|. head bs) : tail bs
Итак, у меня возникает вопрос: как мне написать этот код, чтобы он строил список лениво и без явной рекурсии?
Спасибо за ваше время. .
Редактировать:
На данный момент меня больше всего интересует создание чистого, краткого и нестабильного кода с помощью стандартных комбинаторов. Я все еще новичок в функциональном мышлении и хотел бы увидеть достаточно эффективный способ их применения здесь.