2017-07-31 26 views
3

単一の整数のリストを1つの大きな整数に変換する単純な関数を定義しようとしています。例えば、[1,5,2,0]それはベース10に私が使用することを行うために1520 を返すリストを与えられた:Haskell:2つの引数を持つ関数を定義しようとするとエラーが発生する

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

を今、私はこれができ、異なる拠点にそれを拡張したいです式の基数10を目的の基底に変更することによって行うことができます。そのために、私は別の議論を取り上げ、bをベース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 

型シグネチャのおかげで、コンパイラが今することができ、ので、より明確なエラーメッセージを与える:あなたが再帰呼び出しに少なすぎる引数にfromBaseRepを適用した:

/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 
    |           ^^^^^^^^^^^^^ 

を基本的には問題があり、正確に何を伝えます。残りの数字を再構成するにはどの塩基を知る必要があります!

もう一度bを渡しても問題ありません。

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

私が言ったように、これが原因lengthコールにまだ本当に非効率的です。地元の「ループ機能」goに再帰を委任も、私は明示的bに渡す省略することが許されていること

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

注:この問題を回避するための良い方法は、リストに深く再帰ながら左の数字を乗算することです - これは単にfromBaseRep b = ...バインディングから再利用されています。

これも倍とエレガントに書くことができます。

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

私は本当にGHCはエルムの脚本の外葉を取り、 '考えられる原因を入れてほしい:「fromBaseRep」が少なすぎるarguments'前に適用され、センター。 – SwiftsNamesake

+1

@SwiftsNamesakeまあ、GHCの助言は赤ちゃんなので、GHCは最初に特定の問題について言及し、それに続く原因を考えます。 – chi

+1

確かに。また、「関数fooは2つの引数に適用されますが、その型は... 3つしかありません」という「可能性のある原因」が見られました。 – leftaroundabout

関連する問題