2017-07-31 86 views
3

我想定义一个简单的函数,将单个整数的列表变成一个较大的整数。例如,给出的列表[1,5,2,0]它会返回1520 做,在基地10我用:Haskell:试图用两个参数定义函数时出错

calc_nr [] = 0 
calc_nr (a:y) = a * 10^(length y) + (calc_nr y) 

现在,我想延伸到不同的基础,它可以通过将表达式中的基数10次幂改变为期望的基数来完成。为此,我考虑接受另一个论据b,并以基础权力取代基础权力。
但是,当我尝试这样做时出现了一些错误。写作:

calc_nr b [] = 0 
calc_nr b (a:y) = a * b^(length y) + (calc_nr y) 

给我的错误:

* Occurs check: cannot construct the infinite type: t ~ [t] 
    Expected type: [t] -> t 
    Actual type: t -> [t] -> t 
* Relevant bindings include 
    calc_nr :: [t] -> t (bound at calc_nr.hs:39:1) 

我是新来的Haskell,所以也许这是一个相当愚蠢的错误,但任何帮助将非常感激!

回答

6

首先,一些一般性的建议:

  • 总是写了顶级函数类型签名。这有很多优点(稍后会介绍),但也许最重要的是有人阅读你的代码将理解它应该做什么。您老的固定基地10功能将

    fromBase10rep :: [Int] -> Int 
    

    (你也可以使它通用与其他数字类型除了Int工作,但我不会去成,以保持它的简单。)

  • 避免不必要的括号。

    fromBase10Rep (a:y) = a * 10^length y + calc_nr y 
    
  • 避免length和索引到列表中。这是效率低下的(整个列表需要在每次执行时遍历)。

如果你只要按照第一点,你可能能够回答自己的问题......

fromBaseRep :: Int -> [Int] -> Int 
fromBaseRep b [] = 0 
fromBaseRep b (a:y) = a * b^length y + fromBaseRep y 

因为,由于类型签名,编译器现在可以给出一个更清晰的错误消息:

/tmp/wtmpf-file21653.hs:3:42: error: 
    • Couldn't match expected type ‘Int’ 
        with actual type ‘[Int] -> Int’ 
    • Probable cause: ‘fromBaseRep’ is applied to too few arguments 
     In the second argument of ‘(+)’, namely ‘fromBaseRep y’ 
     In the expression: a * b^length y + fromBaseRep y 
     In an equation for ‘fromBaseRep’: 
      fromBaseRep b (a : y) = a * b^length y + fromBaseRep y 
    | 
3 | fromBaseRep b (a:y) = a * b^length y + fromBaseRep y 
    |           ^^^^^^^^^^^^^ 

基本上,它会告诉你到底是什么问题:您在递归调用应用fromBaseRep太少参数。它仍然需要知道哪个基地重新编号的其余部分!

所以只需再次通过它b,你会没事的。

fromBaseRep b (a:y) = a * b^length y + fromBaseRep b y 

正如我所说的,这仍然是由于length呼叫真的效率低下。一个好办法来解决这个问题是繁衍出左边的数字,而递归深入到列表:

fromBaseRep b = go 0 
where go acc [] = acc 
     go acc (a:y) = go (b*acc + a) y 

注意委派递归当地的“循环功能” go也让我省略明确地传递b - 它只是从fromBaseRep b = ...绑定中重新使用。

这也可以优雅地写成倍:

fromBaseRep b = foldl' ((+) . (b*)) 0 
+0

我真的希望GHC将采取叶出榆木的剧本,并把'可能原因:“fromBaseRep”施加太少arguments'前,中央。 – SwiftsNamesake

+1

@SwiftsNamesake好的,有时来自GHC的建议是一个红色的鲱鱼,所以GHC首选首先提到某个问题,然后跟随一个可能的原因。 – chi

+1

确实。另外,我有几次看到函数foo的“可能原因”被应用于2个参数,但其类型只有3个。 – leftaroundabout

相关问题