2017-07-31 85 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

相關問題