我正在编写一个Haskell函数,该函数在ByteString
值列表上运行。我需要对第一个和最后一个项目执行不同的操作(如果列表只有一个项目,则可能相同)。
具体来说,我想写出以下内容:
"item-1\
\item-2\
\item-3\
...
\item-n"
其中item-1
以双引号开头,以反斜杠结尾,item-n
以反斜杠开头,以双引号结束。 item-1
和item-n
之间的所有项目都以反斜杠开头和结尾。我为一些代码生成发出了一个base64编码的值作为Haskell String
。我已经将原始(长)base64编码的ByteString
分成了每个64个字符长的块。
答案 0 :(得分:11)
我刚才意识到我的问题很愚蠢。
我可以使用intercalate
在项目之间注入"\\\n\\"
,然后在前面添加双引号:
import qualified Data.ByteString.Lazy.Char8 as L
(L.pack "\"") `L.append` (L.intercalate "\\\n\\" items) `L.append` (L.pack "\"")
示例输出:
"H4sIAAAAAA\
\AAA2NgAAMm\
\CMXA7JRYxI\
\Am5JafD2Uy\
\AgDvdHs6Lg\
\AAAA==\
\"
答案 1 :(得分:2)
您还可以考虑使用以下方式拆分列表:
所以[head a] ++ init (tail a) ++ [last a] == a
。
这样,您可以单独更改列表的第一个和最后一个元素,并在“init”部分上映射函数。
答案 2 :(得分:0)
我已经遇到过这种情况好几次了,但是我从来没有找到一个很好的惯用解决方案。有时intercalate
是不够的。这是一个简单的解决方案。
-- | Annotate elements of a list with Bools, the first of which is True if
-- the element is the head of the list, the second of which is True if the
-- element is the last of the list. Both are True for singleton.
markbounds :: [a] -> [(a, Bool, Bool)]
markbounds [] = []
markbounds [x] = [(x, True, True)]
markbounds (x:xs) = (x, True, False) : tailbound xs
where
tailbound [y] = [(y, False, True)]
tailbound (y:ys) = (y, False, False): tailbound ys
例如:
λ> markbounds [1,2,3]
[(1,True,False),(2,False,False),(3,False,True)]
λ> forM_ (markbounds [1,2,3]) $ \(x, isFirst, isLast) -> when isLast $ print x
3
答案 3 :(得分:0)
import Data.List
mapL :: (Bool -> a -> b) -> [a] -> [b]
mapL f l =
map f' $ init $ tails l
where
f' [x] = f True x
f' (x:_) = f False x
尽管现在我考虑的时间稍长一点,但这似乎还不错,甚至更好:
mapL :: (Bool -> a -> b) -> [a] -> [b]
mapL _ [] = []
mapL f [x] = [f True x]
mapL f (x:xs) = (f False x) : mapL f xs
mapL类似于map,但是它所接受的函数具有一个额外的Bool参数,仅在列表的最后一个元素上将其设置为True。
不幸的是,这显然不容易扩展到zipWith,mapM等。 我不知道这有多有效。