1

SMLを使用して特定の整数に等しい整数3タプルのリスト内の要素をカウントしようとしましたが、機能していません。誰かが私が以下のコードの何が問題になっているのかを理解するのを手伝ってくれるか、私のためにそれをまっすぐにすることができますか?

 fun number_in_month(x : int*int*int list, m: int) =
    if null x then 0

         else
           let fun inc x = x + 1;
         in
             val counter = 0;
             if m = #2 (hd x) andalso m > 0 then inc counter
            number_in_month((tl x), m)
           `  else
             number_in_month((tl x), m)
        end

この関数は、mがリスト内の各タプルの2番目の要素に等しい回数を返すことになっています。

4

2 に答える 2

5

明らかに、あなたはあなたの命令的な思考を手放すのに苦労しています。

私はあなたの問題のいくつかに対処しようとしましょう

  • null x、、hd xおよびを使用する代わりに、パターンマッチングを使用する必要がありtl xます。これは、タプルとレコードの分解にも当てはまります。例えば

    fun number_in_month ((x1, x2, x3) :: xs, m) = ...
    

    または、x1とx3を使用したことがないため

    fun number_in_month ((_, x2, _) :: xs, m) = ...
    

    このように、最初の引数は3タプルのリストであり、型の注釈は必要ないことがはっきりとわかります。

    また、明示的な型注釈を省略すると、それはあなたのためにそれらを推測できる型システムを持つという全体的な考えです(次のポイントを参照)、そしてこのコード

    fun foo42 xs = map (fn x => #2 x) xs
    

    「未解決のフレックスレコード」でいくつかの厄介なエラーが表示されます(このエラーメッセージはSML / NJからのものです)

    /tmp/sml20620PlF:105.5-105.44 Error: unresolved flex record
       (can't tell what fields there are besides #2)
    

    3タプルを分解することで簡単に修正できます

    fun foo42 xs = map (fn (_, x2, _) => x2) xs
    
  • タイプアノテーションといえば。それらは(ほとんどの場合)必要ではなく、コードの可読性を乱雑にします。言うまでもなく、それらはあなたが機能するタイプを不必要に制限します。

    また、あなたが与えた型注釈は、あなたが本当に望んでいないことに応じて間違っています。の前後に括弧を付ける必要がありますint * int * int。現在、2つのintとintリストの3タプルとして解釈されますint * int * (int list)

    あなたが本当にあなたの関数に注釈を付けるタイプを主張するなら、あなたはこのようにそれをすることができます

    val number_in_month : (int * int * int) list * int -> int = 
        fn ([]            , m) => 0
         | ((_,x2,_) :: xs, m) => 42
    

    これは「ほぼ」Haskellに似ており、関数宣言の直前に型が指定されます。

  • コードをインデントする方法の一貫性を高めるようにしてください。それはあなたにより良い明快さを与えるでしょう。elseここでは、パーツをインデントした方法を具体的に考えていますin ... end 。以下の部分は、私が想像し始めることができない多くの点で明らかにまだ間違っていますが、それはそれを行う方法としてのアイデアを与えます

    fun number_in_month(x : int*int*int list, m: int) =
        if null x then 0
        else
          let fun inc x = x + 1;
          in
            val counter = 0;
            if m = #2 (hd x) andalso m > 0 then
               inc counter
               number_in_month((tl x), m)
            else
               number_in_month((tl x), m)
          end
    
  • let-expressionval counter = 0の一部の中で変数を宣言することはできません。in ... endlet-expressionのセマンティクスは次のとおりです。

    let
      dec
    in
      exp_1; ...; exp_n
    end
    

    したがって、すべての宣言(関数と値のバインディングなど)はそのlet ... in部分に含まれている必要があります。

  • 地球上でインクリメント機能を持っている必要はありません、それはただ読みやすさを乱雑にします。SMLは単一の代入を使用するため、変数は宣言された後は不変であることに注意してください。

  • ネストされたif式内のシーケンス

    inc counter
    number_in_month((tl x), m)
    

    まったく意味がありません。パーツ内に複数の式を含めることができる唯一の方法 then ... else(実際には、単一の式が期待される任意の場所)は、シーケンス(exp_1; ...; exp_n)を使用することです。ただし、これは、最後の式を除くすべてに副作用がある場合にのみ使用できます。これらの結果は無視されるか、破棄されるためです。

    - (print "Foo\n"; print "Bar\n"; 42);
    Foo
    Bar
    val it = 42 : int
    

ここでSOを少し検索すると、最近、非常によく似た質問が出され回答れていることがわかります。最後の引数のタイプは異なりますが、それでもいくつかの有用なポインターを取得できる場合があります。

全体として、ソリューションは次のようになります

fun number_in_month ([], _) = 0
  | number_in_month ((_,x2,_) :: xs, m) = 
    if x2 = m then
      1 + number_in_month(xs, m)
    else
      number_in_month(xs, m)

ただし、問題は前述の問題よりも単純であるため、基本ライブラリのリストモジュールの高階関数の一部を簡単に使用できます。

fun number_in_month (xs, m) = length (List.filter (fn (_, x2, _) => x2 = m) xs)

または、リストを折りたたんで、一致するたびに途中で変数をインクリメントすることで、さらに(おそらく)簡単になります

fun number_in_month (xs, m) = foldl (fn ((_, x2, _), b) => if x2 = m then b+1 else b) 0 xs
于 2013-01-20T22:41:21.070 に答える
3
fun number_in_month (L : (int*int*int) list, m : int) =
if L = nil
then 0
else
    (if #2 (hd L) = m then 1 else 0) + number_in_month (tl L,m);

テスト:

number_in_month ([] , 2);
number_in_month ([(1,2,3)] , 2);
number_in_month ([(1,2,3),(2,2,2)] , 2);
number_in_month ([(1,2,3),(2,2,2),(19,11,29)] , 2);
number_in_month ([(1,2,3),(2,2,2),(19,11,29),(10,28,19)] , 2);
number_in_month ([(1,2,3),(2,2,2),(19,11,29),(10,2,19)] , 2);
number_in_month ([(1,2,3),(2,2,2),(19,11,29),(10,28,19)] , 2);
number_in_month ([(1,2,3),(2,2,2),(19,11,29),(10,28,19)] , 2);
number_in_month ([(1,2,3),(2,2,2),(19,11,29),(10,28,19),(16,2,7)] , 2);

参照:

http://www.cs.sunysb.edu/~leo/CSE215/smllistexamples.txt

http://www.standardml.org/Basis/list.html

于 2013-11-24T17:30:46.770 に答える