0

在这里完成 noob to haskell,我正在尝试使以下代码工作:

它的目的是获取列表的第一个 exp 元素,将它们连接起来,然后再次调用相同的函数。

order ( i ) (l1)(l2) =
        do exp <- (2 ^  i)
           l <- (take exp l1) ++ (take exp l2 ) ++ (order (i+1) (drop exp l1) (drop exp l2));
           return l

我确信这与惯用的 haskell 相去甚远,但是您必须从某个地方开始。

我得到的错误是

exp <- (2 ^ i ) 

这么说

No instance for (Num [Int])
      arising from a use of `^'
    Possible fix: add an instance declaration for (Num [Int])

我真的不确定这到底意味着什么。不是 2 和 i 都是整数,然后应用求幂函数会得到一个整数吗?

谢谢!

4

3 回答 3

5

I've rewritten your code as follows and added a main.

order _ [] [] = []
order i l1 l2 =
                (take exp l1) ++ (take exp l2)
        ++      (order (i+1) (drop exp l1) (drop exp l2))
        where
        exp = 2^i

main = print $ order 1 [1,2,3,4] [3,4,5,6]

The first mistake you make is that your recursion doesn't terminate as order will always call itself again. The second mistake is in the use of do, this introduces a monad and considering you are new to Haskell, I would stay clear a bit. Use it only for I/O for now.

I hope this helps.

P.S: The error message you are getting is saying that a list of Int is used in a numeric way and there is no default implementation for that. This is probably caused by the do where the monad is over lists, but I'll leave it to cracks in Haskell to give an exact explanation.

于 2013-05-07T23:14:10.267 回答
3

块中的所有语句do必须属于同一个 monad。<-这包括绑定的右侧。因此,因为第二条语句的右手边take exp l1 ++ ...是一个列表,编译器推断出的类型也2^i必须是一个列表。

这是因为<-不仅仅是分配变量。在列表 monad 的情况下,它将左侧的变量顺序绑定到右侧列表的每个元素。

如果您只想在do块中绑定变量而没有任何附加效果,则应使用let绑定而不是<-.

do let exp = 2^i
   l   <- take exp l1 ++ ... 
   return l

也就是说,do这里使用符号是多余的。monad 法则保证do x <- m; return x和 just 一样m,所以你可以直接写成

order i l1 l2 = take exp l1 ++ ...
  where exp = 2^i
于 2013-05-07T23:55:58.140 回答
2

除了 Bryan 的观点,我想我可以帮助解释您遇到该特定错误的原因。

一个重要的原因是,exp <- 2 ^ i在一个do块中并不意味着“让exp作为值的名称2 ^ i”(您可以在 do 块中将这个含义表达为let exp = 2 ^ i,但do无论如何,块并不是您真正想要的)。

意思exp <- 2 ^ i是“让我们exp成为由单子值产生的值的名称2 ^ i”。尝试阅读<-“来自”而不是“是”。“来自”的确切含义取决于所涉及的单子。因此,要使这条线有意义,2 ^ i必须是某种单子中的值。具体来说,它的类型类似于Monad m => m a, 对于未知ma

因为^运算符处理数值,所以它返回类型为 的东西Num a => a。这样我们就可以确定2 ^ i应该是类型的东西(Monad m, Num (m a)) => m a,对于未知的ma

exp是从这个奥秘中提炼出来的m a,所以是有型的a。下一行包括像take exp l1. take要求它的第一个参数是类型的Int,因此exp必须是类型的Int,因此我们可以判断a我们正在使用的未知数必须是Int。所以2 ^ i现在已知是类型(Monad m, Num (m Int)) => m Int;它是某种一元整数。

在这一行中,您也有l <- (take exp l1) ++ .... 所以l也“来自”某种单子价值。可以看到右侧是某种列表(由于使用++takedrop)。块中涉及的 monaddo必须始终相同,列表类型构造函数确实是一个 monad。因此,如果(take exp l1) ++ ...是某物的列表,那么2 ^ i也必须是某物的列表。

所以现在我们有了2 ^ i类型[Int](我们最初知道它是m a;m是列表类型构造函数[],而ais Int)。但我们也知道(从^运算符的使用)它必须是Num类型类的成员。没有Numfor 的实例[Int],这正是您得到的错误。

这只是可以从您编写的代码中得出的许多不一致之处之一;这只是 GHC 在尝试分析它时碰巧遇到的第一个。

于 2013-05-08T01:00:26.227 回答