【问题标题】:Haskell error with a replicate-like function具有类似复制功能的 Haskell 错误
【发布时间】:2014-02-18 12:02:18
【问题描述】:

我想编写一个类似复制的函数:

repli "the" 3 = "ttthhheee" 和 回复“杰森”4 =“jjjjaaaassssoooonnnn”

这是我写的代码:

myrepli []  n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))


repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n)

我得到的错误是这样的:

Couldn't match expected type `[a]' against inferred type `Char'
     Expected type: [[a]]
     Inferred type: [Char]
   In the first argument of `repli', namely `"jason"'
   In the expression: repli "jason" 3

我该如何解决这个问题?谢谢。

【问题讨论】:

  • repli xs n = concatMap (replicate n) xs = flip (concatMap . replicate) xs n.

标签: haskell replicate


【解决方案1】:

对于类型问题,这里有一个对我帮助很大的技巧。每当我对这样的消息感到完全困惑时,我都会执行以下操作:

  • 如果有问题的函数上有类型签名,请将其删除并查看是否有任何变化。如果它编译,询问 ghci 类型是什么(使用:t)。如果它没有编译,至少错误消息可能会有所不同,足以给你另一个线索。
  • 如果没有类型签名,请添加一个。即使它没有编译,错误信息也可能会给你另一个线索。
  • 如果这没有帮助,则暂时在函数中的每个表达式上添加类型声明。 (通常您需要分解一些表达式以查看实际情况。您可能还需要临时启用ScopedTypeVariables pragma。)再次编译并检查错误消息。

最后一个是更多的工作,但我从那个练习中学到了很多东西。它通常会指出我认为的类型与 GHC 认为的类型之间不匹配的确切位置。

让我们从在代码中添加类型签名开始吧:

myrepli :: [a] -> Int -> [a]
myrepli []  n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))


repli :: [a] -> Int -> [a]
repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n) -- triggers a compiler error

啊,现在我们得到一个编译器错误:

amy.hs:9:27:
    Couldn't match expected type `a' with actual type `[a]'
      `a' is a rigid type variable bound by
          the type signature for repli :: [a] -> Int -> [a] at amy.hs:7:10
    In the first argument of `myrepli', namely `x'
    In the first argument of `(++)', namely `(myrepli x n)'
    In the expression: (myrepli x n) ++ (repli xs n)

问题在于对myrepli x n 的调用。函数myrepli 需要一个列表/字符串,但你传递给它一个字符。将最后一行更改为:

repli (x:xs) n = (myrepli [x] n) ++ (repli xs n)

此时您会在代码中发现其他错误。但是,与其修复您的代码,让我向您展示另一种方法:

repl (x:xs) n = (myReplicate x n) ++ (repl xs n)
repl [] _ = []

-- You could use the library function "replicate" here, but as a
-- learning exercise, we'll write our own.
myReplicate a n = take n (repeat a)

【讨论】:

  • 更短的最终解决方案:repl xs n = xs >>= (replicate n)(如果您愿意,可以将replicate 替换为myReplicate)。
  • repl xs n = concatMap (replicate n) xs
  • 或者如果您交换参数的顺序(即repl 3 "the"),您可以使用无积分版本repl = (=<<) . replicate
  • 从这个问题来看,我怀疑 Jason 在某种程度上是 Haskell 的初学者。他可能还没有学习过无点表示法或绑定运算符。
  • @mhwombat,关于你的第一点 - 关于 haskell 编译器的有趣之处在于,如果你在函数上有一个类型签名并且它出错了,它并不是说你的签名是错误的,而是你的程序是错误的,并且签名是正确的!因此,我们删除签名以查看它是否可以编译! :-)
【解决方案2】:

myrepli 需要一个 list 和一个整数。但是,repli 的定义用x 调用它,这是一个项目,而不是项目的列表

我想你要么想改变myrepli以将单个项目作为参数,或者你想改变repli以传递[x]而不是只是x。 (我建议前者而不是后者。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    • 2012-12-18
    • 1970-01-01
    • 2022-01-17
    相关资源
    最近更新 更多