2013-05-07 52 views
0

完整的小白在这里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 

我敢肯定,这远不是惯用的哈斯克尔,但你必须从一些地方开始。

我得到的错误是在

exp <- (2^i) 

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

这我真的不能确定这究竟意味着。是不是2和我的整数,然后应用指数函数将导致一个整数?

谢谢!

回答

5

我重写了你的代码,如下所示,并添加了一个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] 

所做的第一个错误是,你的递归不会终止为order总会再次调用本身。第二个错误是在使用do时,这引入了一个monad并且考虑到你是Haskell的新手,我会保持清醒一点。现在只用于I/O。

我希望这会有所帮助。

P.S:您收到的错误消息是说,Int的列表以数字方式使用,并且没有默认实现。这可能是由于monad超出列表的do造成的,但是我将在Haskell中对其进行分解以给出准确的解释。

3

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

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

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

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

也就是说,这里使用的do表示法是多余的。单子法律,保障了do x <- m; return x是一样的只是m,所以你可以直接把它写成

order i l1 l2 = take exp l1 ++ ... 
    where exp = 2^i 
2

除了布莱恩的点,我想我可以帮助解释你得到的特定错误的原因。

很大的原因是exp <- 2^ido块不意味着“让exp是的2^i值名称”(你会表达一个do块为let exp = 2^i这个意思,但do块ISN”反正你真正想要的是这里)。

什么exp <- 2^i的含义是“让exp成为由一元值2^i产生的值的名称”。尝试阅读<-作为“来自”而不是“是”。究竟“来自”意味着取决于所涉及的monad。所以对于这条线意味着什么,2^i必须是某种monad中的值。具体来说,它的类型就像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也“来自”某种monadic价值。可以看到右侧是某种列表(由于使用了++,takedrop)。参与do块的monad必须始终相同,并且列表类型构造函数确实是monad。所以如果(take exp l1) ++ ...是一个东西的列表,那么2^i也必须是一个东西的列表。

所以现在我们有2^i存在[Int]类型的(我们原先知道这是m a;该m是列表类型构造[]aInt)。但是我们也知道(使用^运算符)它必须是Num类型类的成员。 [Int]没有Num的实例,这正是你得到的错误。

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