【问题标题】:Do notation in haskell在haskell中做符号
【发布时间】:2018-04-27 12:26:33
【问题描述】:

所以我正在尝试在 haskell 中编写一个函数,该函数执行以下操作: 1.输入是一个字符串 2.函数首先删除字符串的所有字母,只剩下数字 3.函数将字符串数字转换为int数字 4.函数将字符串中的数字相加并打印出来

我的代码直到第 3 步

func str = 
    do 
    str <- filter (< 'a') str
    str2 <- map digitToInt str
    return str2

如果我用 map digitToInt 删除第 4 行,它会以某种方式不起作用,直到第 2 步正常,但我不知道这里的问题是什么

错误是无法将预期类型 [Char] 与实际类型 Char 匹配

提前谢谢你

【问题讨论】:

  • 示例输入“45abc”输出9

标签: haskell


【解决方案1】:

你根本不需要do 符号,只是普通的变量绑定。所以:

func str = str2 where
    str1 = filter (<'a') str
    str2 = map digitToInt str1

跟踪最近使用的名称很烦人,不是吗?另外,很容易出错并在某处输入str 而不是str1 或类似名称。输入函数组成:

func str = str2 where
    str2 = (map digitToInt . filter (<'a')) str

其实我会内联str2的定义,然后完全省略str

func = map digitToInt . filter (<'a')

我更喜欢使用isDigit 而不是(&lt;'a');我们可以同时折腾一笔。

func = sum . map digitToInt . filter isDigit

在我看来,读起来很干净。

【讨论】:

    【解决方案2】:

    可以使用do 表示法,因为字符串是列表,而列表是单子。不过看起来应该是这样的:

    func :: String -> [Int]
    func str = do
      c <- filter (< 'a') str  -- Get one character
      return (digitToInt c)    -- Change that character to a integer
    

    c 的值是多少?这不仅仅是一个角色,而是所有个角色。列表单子模型非确定性。想象func 制作了多个自身副本,每个副本从输入字符串中选择不同的字符creturn 从结果中创建一个新列表,monad 负责将各个列表粘合到一个最终列表中。如果你比较一下它的解构形式,它会更清楚一些。

    func str = filter (< 'a') str >>= \c -> return (digitToInt c)
    

    由于Monad [] 实例中的xs &gt;&gt;= f = concatMap f xsreturn x = [x],它变为:

    func str = concatMap (\c -> [digitToInt c]) (filter (< 'a') str)
    

    但是,单子形式不是必需的,因为您的函数只需要使用[]Functor 实例,因为第一个列表中的每个元素都对应于最终列表中的一个元素:

    -- Or in a form closer to Daniel Wagner's answer
    func str = fmap digitToInt (filter (< 'a') str)
    

    【讨论】:

    • 是的。我认为这应该提前发出一个很大的警告,尽管这种使用 do 表示法的行为与人们在命令式语言中所期望的完全不同。
    • @leftaroundabout 如果首先将“do”命名为“for”(for s in getString: print sfor s2 in (for s in getString: yield (s++"!")): print s2for c in "string": [c,c]),那根本就不是问题。溢出的牛奶,是的。
    • @WillNess 认真的吗?该语法看起来远不及当前的do 语法。 yield 而不是 return 当然更可取(那个实际上很容易更改),但 for 似乎比大多数 monad 更糟糕的关键字选择,比 do 更具误导性。
    • @leftaroundabout 我没有发现问题。但也可以是with s from getString:with c from "string": 等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 2022-12-06
    • 2010-11-23
    相关资源
    最近更新 更多