標準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 を作成することはできません。そこで、再帰的なヘルパー関数を作成し、再帰中に変化する引数を持たせます (継承するだけmonth2
でcount
、 の親スコープからnumber_in_month
取得できます。再帰が終了すると (基本ケース)、ref-cell 内の値を返すことを選択します)。 (逆参照のために標準 ML のやや不明瞭な構文を使用します)。
機能的な方法を習得する前に、ref-cells を使用することを習慣にしないでください。そうしないと、この習慣を醜くする言語での命令型コーディングに戻ることになります。:)