Haskell映射(?)操作具有不同的第一个和最后一个函数

时间:2013-01-01 20:35:52

标签: haskell map split base64

我正在编写一个Haskell函数,该函数在ByteString值列表上运行。我需要对第一个和最后一个项目执行不同的操作(如果列表只有一个项目,则可能相同)。

具体来说,我想写出以下内容:

  "item-1\
  \item-2\
  \item-3\
  ...
  \item-n"

其中item-1以双引号开头,以反斜杠结尾,item-n以反斜杠开头,以双引号结束。 item-1item-n之间的所有项目都以反斜杠开头和结尾。我为一些代码生成发出了一个base64编码的值作为Haskell String。我已经将原始(长)base64编码的ByteString分成了每个64个字符长的块。

4 个答案:

答案 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”获取列表的第一个元素
  • “tail”获取列表的第一个元素
  • “init”获取列表的最后一个元素
  • “last”获取列表的最后一个元素

所以[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等。 我不知道这有多有效。