1

更新: このコードでやりたいことは、日付、年/月/日、および月として指定された数値のリストを取得し、指定されたリスト内の日付のうち何月が同じ月にあるかを確認することです。その月。x = x + 1 の意味は、Java や C、C# などの x++ でした。出力として x が必要です。一致がない場合は 0、一致する場合は x = x + 1

これが私のコードです。

fun number_in_month (Dlist : (int * int * int) list, Month : int, x : int) =
   if null Dlist then x
   else if #2 (hd Dlist) = Month then x = x + 1 andalso number_in_month (tl(Dlist), Month, x)
        else number_in_month ((tl(Dlist)), Month, x)

そして、それは私にエラーを与えます:

Error: types of if branches do not agree [tycon mismatch]
      then branch: int
      else branch: bool
       in expression:
       if null Dlist
       then x
       else if (fn <rule>) (hd <exp>) = Month
            then (x = <exp> + <exp>)
                  andalso (number_in_month (<exp>,<exp>,<exp>))
            else number_in_month (tl <exp>,Month,x)

sml が bool 型の x = x + 1 を考慮している理由がよくわかりません。x = x + 1 を sml で正しく言う方法を誰かが教えてくれたら、本当にうれしいです。よろしくお願いします。

4

1 に答える 1

4

標準MLx = x + 1で言うと、明らかに意図していないことを意味するため、何を意図しているかを明確にする必要がありますx = x + 1。それが意味するのは、「比較xしてx + 1、等しいかどうかを言う」ことです(決して整数にはなりません)。

あなたが達成したいと思うのは、「x をその後継者に更新する」ことです。これは、参照型を使用しないと不可能です。参照型は不変で機能的ではないため、お勧めしません。何かを機能的に更新する通常の方法は、更新された値を、最終的にそれを返す関数に渡すことです。(関数の引数を累積変数として使用するため、再帰呼び出しごとに値を更新するのと同じ変数であるかのように感じます。)

もう 1 つお勧めするのは、if-then-else の代わりにパターン マッチングを使用することです。たとえば、リストが一致する場合、リストが空であることがわかります[]計算の結果はブール値ではないため、「... andalso ...」は使用できません。「一度に2つのことをしたいのに、何かをしているようなにおいがする」という理由でこれを行うのではないかと思います。これは ( eg ;orを使用してbefore) 実行できますが、これらの演算子は副作用を処理し、オペランドの 1 つの主効果を破棄するため、結果が失われます。この時点であなたが望むものではありません。

これは、パターン マッチングを使用して記述された、あなたが意図したものに対する暗闇の中での私の刺し傷です。

fun number_in_month ([], _, x) = x
  | number_in_month ((one,two,three)::dlist, month, x) =
    if two = month then number_in_month(dlist, month, x+1)
                   else number_in_month(dlist, month, x)

変更:末尾再帰なしでこれを行うこともできます

fun number_in_month([], _) = 0
  | number_in_month((_,month1,_)::dlist, month2) =
    if month1 = month2 then 1 + number_in_month(dlist, month2)
                       else number_in_month(dlist, month2)

または別の書き方:

fun number_in_month([], _) = 0
  | number_in_month((_,month1,_)::dlist, month2) =
    (if month1 = month2 then 1 else 0) + number_in_month(dlist, month2)

またはリストコンビネータを使用します:

fun counter(n1,n2) = if n1 = n2 then 1 else 0
fun number_in_month(dlist, month2) =
    foldl (fn ((_,month1,_),count) => counter(month1,month2) + count) 0 dlist

または、あなたが求めたように、参照を使用しますが、私はこれを思いとどまらせます:

fun number_in_month (dlist, month2) =
    let val count = ref 0
        fun loop [] = !count (* the value inside the ref-cell *)
          | loop ((_,month1,_)::dlist) =
            if month1 = month2 then (count := !count + 1 ; loop dlist)
                               else loop dlist
    in loop dlist end

ご覧のとおり、関数内で ref-cell を作成したいので、複雑さが増しますが、再帰呼び出しのたびに新しい ref-cell を作成することはできません。そこで、再帰的なヘルパー関数を作成し、再帰中に変化する引数を持たせます (継承するだけmonth2count、 の親スコープからnumber_in_month取得できます。再帰が終了すると (基本ケース)、ref-cell 内の値を返すことを選択します)。 (逆参照のために標準 ML のやや不明瞭な構文を使用します)。

機能的な方法を習得する前に、ref-cells を使用することを習慣にしないでください。そうしないと、この習慣を醜くする言語での命令型コーディングに戻ることになります。:)

于 2013-10-12T08:40:50.343 に答える