Haskell:如何将字符串转换为布尔矩阵

时间:2013-11-06 17:26:07

标签: haskell matrix type-conversion

我需要一些Haskell的帮助。 我想读取一个字符串并将该字符串转换为布尔值列表的列表。 例如,"LLL\nbbb\nLLL"应生成以下列表:[[True,True,True],[False,False,False],[True,True, True]]。应该忽略任何其他事情。

我是函数式编程的新手。我尝试了以下方法:

StringParse :: String -> Matrix
StringParse s =
    case s of
            "L" -> Matrix [[True]] 
            "b" -> Matrix [[False]]

使用数据类型Matrix:

data Matrix = Matrix [[Bool]]

3 个答案:

答案 0 :(得分:5)

您首先在子问题中拆分任务。

  • 在每个换行符的块中对列表进行分区。很简单,有一个标准函数就是这样:lines
  • 删除任何你不想要的东西。这可能是filter的工作。
  • 将每个L转换为True值,每个b转换为False。这只是map操作。
  • 需要为每个块/行执行前两个步骤,因此您需要再次使用map将它们应用于行列表。
  • 将所有内容打包到Matrix数据构造函数中。

在Haskell中将所有链接在一起非常容易:

parse :: String -> Matrix
parse = Matrix . map (map decide . filter isKnown) . lines
 where decide 'L' = True
       decide 'b' = False
       isKnown 'L' = True
       isKnown 'b' = True
       isKnown _ = False

这将是一个非常好的解决方案。

实际上,在这里合并第二步和第三步可能更好:不是首先挑选我们可以处理的值,然后在单独的情况下处理相同的值集,我们可以同时做两个时间。 IMO最好的方式,虽然它现在可能让你困惑,但是使用列表是monad的事实:

parse' :: String -> Matrix
parse' = Matrix . map translate . lines
 where translate line = do
         ch <- line
         case ch of 'L' -> [True]
                    'b' -> [False]
                    _   -> []

答案 1 :(得分:4)

让我们把它分解成小步骤。

您想将"LLL\nbbb\nLLL"之类的字符串转换为Matrix [[True, True, True], [False, False, False], [True, True, True]]。这意味着您希望将该字符串转换为[[True, True, True], [False, False, False], [True, True, True]],然后将其包装在Matrix中。

这意味着您希望单独处理每一行,因此您需要将"LLL\nbbb\nLLL"转换为["LLL", "bbb", "LLL"]。很简单,Haskell有一个名为lines的内置函数,它将为我们执行此操作,它会在换行符上拆分字符串。那么让我们写下目前为止的内容

parse :: String -> Matrix
parse s = Matrix $ {- something -} lines s

那么我们如何将一条线变成一个布尔列表呢?我们将每个单独的字符转换为布尔值,然后将该操作应用于每个字符。首先,我们应该编写一个辅助函数来匹配我们想要的字符

charToBool :: Char -> Bool
charToBool 'L' = True
charToBool 'b' = False
charToBool _   = False -- Catch-all.  With this you don't actually need the 'b' case

请注意,这会将 Char 转换为Bool。现在我们可以将它映射到整行

lineToBools :: String -> [Bool]
lineToBools line = map charToBool line

现在,我们只需将此操作应用于我们拥有的所有行

parse s = Matrix $ map lineToBools $ lines s

你已经完成了!


有一种更短,更好的方法。首先,除非你真的需要它,不要在构造函数中包装[[Bool]],只需使用类型别名

type Matrix = [[Bool]]

接下来,可以在某种程度上内联这些功能

parse s = map (map charToBool) $ lines s

这可以将ETA缩减为

parse = map (map charToBool) . lines

但是,charToBool也可以内联到(== 'L'),因此您可以将整个内容写为

parse = map (map (== 'L')) . lines

我更喜欢它。


如果您想过滤掉意外的输入,您也可以

parse = map (map (== 'L')) . map (filter (`elem` "Lb")) . lines

并将其保存在一行中。

答案 2 :(得分:2)

parse :: String -> Matrix
parse = Matrix . map (map (=='L') . filter (\x -> x=='L' || x=='b')) . lines

应该做的诀窍:D

编辑:现在应该工作,感谢Tetigi和bheklilr!