【问题标题】:Check every character of a string with guards [Haskell]使用警卫检查字符串的每个字符 [Haskell]
【发布时间】:2020-03-05 01:36:34
【问题描述】:

我在尝试使用 Haskell 时遇到问题。当我看到字符时,我想读取一串数字并打印各种消息。

import System.Environment
import System.Exit
import Data.List
import Control.Monad


test_parse:: [Char] -> IO ()
test_parse [] = putStrLn "\n"
test_parse (a:b:c:xs)
            | a == '1' && b == '2' && c == '3' = putStrLn ("True")
            | a == '2' && b == '3' && c == '4' = putStrLn ("False")
            | a == '4' && b == '5' && c == '6' = putStrLn ("maybe")
            | otherwise = test_parse (b:c:xs)

main = do
    let numbers = "123456"
    let loop = do
            goGlenn <- getLine
            test_parse numbers
            putStrLn goGlenn
            when (goGlenn /= "start") loop
    loop
    putStrLn "ok"

问题是这样的。我想打印“True\nFalse\nMaybe\n”,但我只打印“True\n”。我知道我的问题是,当警卫采取行动时,它会离开功能。但是我不知道如何在不离开 'test_parse 的情况下检查整个字符串。

如果有人有想法,谢谢。

【问题讨论】:

    标签: parsing haskell recursion guard


    【解决方案1】:

    无论前缀上的结果如何,您都想检查每个后缀。一个例子:

    -- output a string based on the first 3 characters of the input
    classify :: String -> IO ()
    classify xs = case take 3 xs of
                    "123" -> putStrLn "True"
                    "234" -> putStrLn "False"
                    "456" -> putStrLn "maybe"
                    otherwise -> return ()
    
    -- call classify repeatedly on different suffixes of the input
    test_parse :: String -> IO ()
    test_parse [] = return ()
    test_parse all@(_:xs) = do
        classify all
        test_parse xs
    

    【讨论】:

    • 好的,但是如果我使用它,我无法选择是否要在打印后放置 \n。基本上,它可以工作,但是如果我们愿意,我们可以删除 \n 吗?
    • 您可以让classify 返回Strings 的列表,而不是实际执行I/O,让test_parse 处理实际输出。
    【解决方案2】:

    为了说明 chepner 关于使 classify 返回 Strings 的列表而不是执行 I/O 的观点:

    import Data.List (tails)
    
    classify :: String -> [String]
    classify s = case take 3 s of
      "123" -> return "True"
      "234" -> return "False"
      "456" -> return "maybe"
      otherwise -> mempty
    
    classifyAll :: String -> [String]
    classifyAll s = tails s >>= classify
    
    main :: IO ()
    main = interact (unlines . classifyAll)
    

    运行这个,

    $ stack ghc classify.hs
    $ echo 123456 | ./classify
    True
    False
    maybe
    

    我无法选择是否要在打印后放置 \n。

    基本上,它可以工作,但是如果我们愿意,我们可以删除 \n 吗?

    如果你想用换行符以外的东西来分隔,

    import Data.List (intercalate, tails)
    
    ...
    
    main :: IO ()
    main = interact ((++ "\n") . intercalate ", " . classifyAll)
    

    运行这个,

    $ echo 123456 | ./classify
    True, False, maybe
    

    拆分解析和打印的代码还可以使您的代码更易于测试。例如

    spec_classify :: Spec
    spec_classify =
      describe "classify" $
        it "classifies 123, 234 and 456" $
          classifyAll "123456" `shouldBe` ["True", "False", "maybe"]
    

    对此进行测试,

    $ stack ghci classify.hs
    > hspec spec_classify 
    
    classify
      classifies 123, 234 and 456
    
    Finished in 0.0005 seconds
    1 example, 0 failures
    

    【讨论】:

      猜你喜欢
      • 2019-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多