3

私は次のコードを持っています:

betaRest :: Int -> [Int] -> Int
betaRest n prevDigits | n == 0    = (length prevDigits)
                      | otherwise = (sum (map (betaRest (n - 1)) [0..9]))

betaFirst :: Int -> Int
betaFirst n | n == 0    = 0
            | otherwise = (betaRest (n - 1) [1..9])

次のエラーが発生しますが、理由はわかりません。

1)等差数列 '0 .. 9'から生じる(Enum [Int])のインスタンスはありません

2)リテラル「0」から生じる(Num [Int])のインスタンスはありません

Haskellは「..」演算子で作られたものは列挙だと思いますか?しかし、4行下の行(「[1..9]」を含む)にエラーがないのはなぜですか?


編集:私がコードに実行させたいことは次のようになります(手続き的に):

int betaRest(int n, int[] prevDigits) {
  if (n == 0) return prevDigits.length;
  else {
    sum = 0;
    foreach prevDigit in prevDigits {
      sum += betaRest(n - 1, [0..9]);
    }
    return sum;
  }
}

int betaFirst(int n) {
  if (n == 0) return 0;
  else return betaRest(n - 1, [1..9]);
}

したがって、betaFirst(1)== 9、betaFirst(2)== 90です。はい、誰かがこれを生成するための式を提案したいと思うかもしれませんが、[0..9にある種のフィルターを追加します。 ]、したがって範囲を縮小します。

4

2 に答える 2

4

に渡しbetaRestますmap。マップは(a -> a) -> [a] -> [a]リストの[Int]場合、渡すとInt -> Int関数が必要になります。ただし、部分的に適用されるbetaRestのは[Int] -> Int.

その[0..9]型は is(Enum t, Num t) => [t]であり、アプリケーションに変換されenumFromTo 0 9ます。そのため、コンパイラはあなたのエラーを逆に考えました.リストの特別なインスタンスを定義するNumEnum[0..9]intのリストのリストになり、アプリケーションは理にかなっています.

しかし、私はあなたが使いたいinitstails機能したいと思います。解決をお手伝いできるように、達成したいことをお知らせください。

最小限の修正は、未使用を無視するためにラムダ抽象化をprevDigits引数として追加して使用することです。mapprevDigit

   | otherwise = sum (map (\prevDigit -> betaRest (n - 1) [0..9]) prevDigits)
于 2012-10-02T07:01:48.003 に答える
2
(sum (map (betaRest (n - 1)) [0..9]))

括弧の数を減らして、何が起こるかをよく見てみましょう。

sum (map (betaRest (n - 1)) [0..9])

の引数sum

map (betaRest (n-1)) [0 .. 9]

さて、betaRest :: Int -> [Int] -> Intしたがって、部分的に適用された関数の型は

betaRest (n-1) :: [Int] -> Int

したがって、型を推測できます

map (betaRest (n-1)) :: [[Int]] -> [Int]

しかし、 に渡される引数は でmap (betaRest (n-1))あり[0 .. 9]、これには型があります

[0 .. 9] :: (Num a, Enum a) => [a]

Num制約は整数リテラルの使用に由来し、制約EnumenumFromTo関数の使用に由来します (その構文糖化形式で[low .. high])。型の引数を期待する関数に引数としてそれを渡すこと[[Int]]は、型変数aを としてインスタンス化する必要があることを意味し[Int]、次に制約をチェックする必要があります。つまり、[Int]forNumとのインスタンスをEnum検索する必要があります。これらはどちらも存在しないため、エラーメッセージが表示されます。

あなたの手続き例が本当にあなたが望むものであるかどうかはわかりませんが、

int betaRest(int n, int[] prevDigits) {
  if (n == 0) return prevDigits.length;
  else {
    sum = 0;
    foreach prevDigit in prevDigits {
      sum += betaRest(n - 1, [0..9]);
    }
    return sum;
  }
}

ループは、次のforeachように表現する方がはるかに簡単 (かつ効率的) です。

sum = prevDigits.length * betaRest(n-1, [0 .. 9]);

したがって、が意味をなすためには、ループ本体にforeach依存関係が必要です。prevDigit

Haskell への翻訳は次のようになります。

betaRest n prevDigits
    | n == 0    = length prevDigits
    | otherwise = length prevDigits * betaRest (n-1) [0 .. 9]
    -- or with the loop, with the small improvement that `betaRest (n-1) [0 .. 9]
    -- is only computed once (if the Haskell implementation is sensible)
    -- | otherwise = sum $ map (const $ betaRest (n-1) [0 .. 9]) prevDigits

しかし、上で述べたように、それが本当にあなたが望んでいることだとは思えません。

于 2012-10-02T12:04:54.633 に答える