繁体   English   中英

获取[Char]而不是IO()字符串

[英]Getting [Char] instead of IO() String

我是Haskell的新手。 我正在读取输入字符串(a),并且想在其中找到字符(e)时返回一个字符串。 现在我的整个源代码:

a = "b,b,b,b/b,b,b/b,b,b,b/e,e,e/w,w,w,w/w,w,w/w,w,w,w"
n = length a

simpleCase n =
    case n of
        'a' -> "hey cutie"

eLoopCase i =
    if i < n
        then do
            let char = a !! i
            case char of
                'e' -> putStr $ "(" ++ "found an e" ++ "),"
                'w' -> return ()
                'b' -> return ()
                ',' -> eLoopCase (i+1)
                '/' -> eLoopCase (i+1)
            if (char == ',' || char == '/') == False
                then eLoopCase (i+1)
                else return ()
        else return ()

simpleCase给了我一个字符串,但是eLoopCase给了我一个IO()。 它可以工作,但是我希望eLoopCase返回一个String以便我可以处理它。

:t simpleCase 
simpleCase :: Char -> [Char]
:t eLoopCase 
eLoopCase :: Int -> IO ()

我知道这与monads有关, then doputStrputStr ,这就是我的理解的终点。 删除do会导致解析错误。

eLoopCase不返回任何内容,因为您在它的所有“末端”都具有return () 我认为您正在执行类似这样的操作(注意,将当前字符附加到x == 'w' || x == 'b'分支中的递归调用的结果中):

a :: String
a = "b,b,b,b/b,b,b/b,b,b,b/e,e,e/w,w,w,w/w,w,w/w,w,w,w"

eLoopCase :: String -> IO String
eLoopCase [] = return []
eLoopCase (x:xs)
  | x == 'e' = do
      putStrLn "(found an e)"
      return [x]
  | x == ',' || x == '/' =
      eLoopCase xs
  | x == 'w' || x == 'b' = do
      rest <- eLoopCase xs
      return (x : rest)
  | otherwise = do
      putStrLn ("Encountered invalid character: " ++ show x)
      return []

您的代码的一般问题:

  • 您编写的程序的风格非常重要。 这是我敦促您在编写Haskell时尝试摆脱的东西。
  • 优先使用列表上的模式匹配而不是使用!!

我应该注意,我提供的功能有其自身的缺陷。 它假定提供给它的字符串将仅包含几个不同的字符。 一种改进方法是向警卫队添加otherwise分支。 (编辑:已添加到上面的代码段中)

我认为还值得指出的是,此功能实际上完全不需要依赖IO来工作。 查看其他用于执行错误处理/报告的“纯”替代方法,例如EitherMaybeWriter

很高兴您决定尝试学习Haskell。 您可以比eLoopCase做得更好。 我将告诉您如何操作,但是首先我将说明您在原始问题中遇到的问题以及如何解决。

如最初所写,eLoopCase的类型为Int- Int -> IO () ,这意味着它是一个接受Int并返回输入输出动作的函数。 IOW,该类型告诉您,如果给它一个数字,它将执行某些操作 如果看一下代码,您会发现有些东西只是在打印字符串,但实际上几乎什么都没有。

在您的答案中,您重写了eLoopCase以直接通过++运算符构造字符串,而不是通过putStr将它们打印到终端。 这就是您重写的函数具有其类型的原因。 它还说明了为什么不再需要return ()语句,它们是“在返回()值时不执行任何操作” IO操作。

我希望这可以使事情变得简单。 也就是说, eLoopCase可以得到极大的改进。

当控制逻辑与数据结构匹配时,可以高效地编写Haskell程序。 例如,此程序正在遍历列表。 列表定义为数据,它可以是空列表,也可以是元素列表和更多列表,如下面的声明所示。

data List a = []
            | a : List a

因此,遍历列表的程序将基于这两个构造函数的决策。 例如(使用[Char]的同义词String ),可以将eLoopCase重写为

eLoopCase' :: String -> String
eLoopCase' []     = ""
eLoopCase' (a:as) = evalCase a ++ eLoopCase' as

evalCase a = case a of
  'e' -> "(" ++ "found an e" ++ "),"
  'w' -> ""
  'b' -> ""
  ',' -> ""
  '/' -> ""
  _   -> ""

请注意, eLoopCase'不再被硬编码到函数的主体中,因此需要将a作为输入输入,这是一件好事。 它还消除了索引i和使用!!引起的错误!! (尝试调用eLoopCase (-1) )。

有编写eLoopCase'等递归函数的实践是一个好的开始。 编程的一个发展就是看到您打算对该循环进行处理并应用适当的模式。

例如,由于您要通过某个函数评估列表中的每个元素,因此请使用map 具体来说, map evalCase为从字符列表到字符串列表,然后使用concat将所有这些列表附加在一起:

eLoopCase'' = concat . map evalCase

其实我已经回答了我自己的问题。 以下似乎有效:

a = "b,b,b/b,b,b/b,b,b,b/e,e,e/w,w,w,w/w,w,w/w,w,w,w"
n = length a

eLoopCase i =
    if i < n
        then
            case a !! i of
                'e' -> "(" ++ "found an e" ++ ")," ++ eLoopCase (i+1)
                'w' -> "" ++ eLoopCase (i+1)
                'b' -> "" ++ eLoopCase (i+1)
                ',' -> eLoopCase (i+1)
                '/' -> eLoopCase (i+1)
        else ""

我仍然对发生的事情感到好奇。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM