コードが入力されていないことに言及していません。
最初の関数句にはl1
、再帰で使用される変数が含まれているだけです。ただし、ここでは、引数として指定されたトリプルの最初の要素として使用されます。これは、SML が使用する Hindley-Milner 型システムと実際には連携していません。これは、おそらく次の非公式の考えでよりよく理解できます。
l1
が typeであると仮定することから始めましょう。'a
したがって、関数はその型の引数を取り、不明なものを返す必要があります'a -> ...
。ただし、右側で(l1, [], [])
は、型を持つ必要がある引数を作成します'a * 'b list * 'c list
。しかし、これは引数として関数に渡されるため、'a
が と等しいことも意味するはず'a * 'b list * 'c list
ですが、明らかにそうではありません。
明らかに、これはあなたの当初の意図ではありませんでした。あなたの意図は、リストを引数として取る関数を持ち、同時に2つの追加の累積引数、つまり元のリストの正と負の数のリストを取る再帰ヘルパー関数を持つことだったようです。
これを行うには、少なくともヘルパー関数に別の名前を付けて、その定義が元の関数の定義を再バインドしないようにする必要があります。次に、このヘルパー関数をどのスコープに含めるかについて、いくつかのオプションがあります。一般に、「メイン」関数以外からこのヘルパー関数を呼び出すことに意味がない場合は、 「メイン」関数の外側のスコープ。これは、次のような let バインディングを使用して実行できます。
fun positive xs =
let
fun positive' ys p n = ...
in
positive' xs [] []
end
この方法では、ヘルパー関数を関数positives'
の外で呼び出すことはできませんpositive
。
これにより、元のコードにさらにいくつかの問題があることに注意してください。
正の整数のリストのみを返すため、負の整数を追跡する必要はありません。
リスト要素を分解するには、パターン マッチングを使用する必要があります。このようにして、リストの先頭と末尾を取得する必要がなくなり、リストに実際に先頭と末尾があるかどうかを確認する必要もなくなります。
fun foo [] = ... (* input list is empty *)
| foo (x::xs) = ... (* x is now the head, and xs is the tail *)
追加演算子 ( @
) は、回避できる場合はいつでも使用しないでください (常に回避できます)。問題は、左側に巨大なリストがあり、右側に小さなリストがある場合、実行時間がひどいことです (これは右側の場合によくあります。単一要素)。したがって、一般に、それを使用することは悪い習慣と見なされるべきです。
ただし、これには非常に簡単な解決策があります。これは、常にリストの前に要素を連結し (リストを逆の順序で構築)、最後にリストを返すときにリストを逆にする (期待される順序にする) ことです。 ):
fun foo [] acc = rev acc
| foo (x::xs) acc = foo xs (x::acc)
これらの小さなメモを考えると、最終的には次のような関数になります
fun positive xs =
let
fun positive' [] p = rev p
| positive' (y::ys) p =
if y < 0 then
positive' ys p
else
positive' ys (y :: p)
in
positive' xs []
end