2

我需要一些有关 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]]

使用数据类型矩阵:

data Matrix = Matrix [[Bool]]

4

3 回答 3

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

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

实际上,在这里合并第 2 步和第 3 步可能会更好:与其先挑选我们可以处理的值,然后用不同的情况处理相同的值集,我们可以同时做这两个步骤。IMO 最好的方法,虽然现在可能让您感到困惑,但使用列表是 monad 的事实:

parse' :: String -> Matrix
parse' = Matrix . map translate . lines
 where translate line = do
         ch <- line
         case ch of 'L' -> [True]
                    'b' -> [False]
                    _   -> []
于 2013-11-06T17:37:49.107 回答
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

这可以减少到

parse = map (map charToBool) . lines

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

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

我更喜欢。


如果你想过滤掉意外的输入,你也可以这样做

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

并将其保留在一行中。

于 2013-11-06T17:38:19.677 回答
2
parse :: String -> Matrix
parse = Matrix . map (map (=='L') . filter (\x -> x=='L' || x=='b')) . lines

应该做的伎俩:D

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

于 2013-11-06T17:42:04.883 回答