2

2特定のソートされたリストで最初の要素を割った値よりも大きい要素の数を見つける関数を作成しようとしています。たとえば、リストが与えられた場合[3,3,4,5,6,7,8,9,11]、最初の要素は3であり、より大きな数を で割ると、関数2は を7,8,9,11返します4

私はこれまでこれを行ってきましたが、うまくいきません。このa要素はリストの最初にあり、簡単にするために指定されています。

fun findlarger a [] =
  | findlarger [] = 0
  | findlarger [x] = 0
  | findlarger (x::xs) =
    let
      val a = ref a;
    in
      if !a < x/2 then length (xs) + 1 else findlarger (a, xs)
    end
4

2 に答える 2

3

あなたのコードの問題点をどこから指摘したらよいかさえわかりません。関数型プログラミングの基本を誤解しているようです。

  • まず、参照を使用すべきではありません (自分が何をしているのかわかっていない限り、おそらくまだ間違っている可能性があります)、再帰を使用する必要があります。
  • 同じ数の引数を取るように関数を宣言していません。最初の節では、2 つのカリー化された引数を使用して定義し、残りの節では 1 つの引数しか持たず、コードの最後の 2 行目では、ペアを引数として関数を呼び出しています。
  • 最初の関数句には本体がありません。
  • "<"sml の厳密なより小さい演算子ではありません。あなたがそこに書いたように、それは文字列です。

元のコードを修正すると、このような結果になります。最初の要素は常にリストに戻されることに注意してください。これにより、何と比較するかがわかります。

fun findlarger [] = 0
  | findlarger [x] = 0
  | findlarger (x::y::xs) =
    if y > x*2 then
      1 + findlarger(x :: xs)
    else
      findlarger(x :: xs)

ただし、内部ヘルパー関数を使用して x*2 の計算を行うこともできるため、毎回計算されるわけではありません。

fun findlarger [] = 0
  | findlarger (x::xs) =
    let
      val xx = 2*x
      fun f [] = 0
        | f (y::ys) =
          (if y > xx then 1 else 0) + f ys
    in
      f xs
    end

他の回答で提案されているように高次関数を使用する場合は、リストを2回トラバースすることを避ける必要があります(最初に要素を除外してから残りを数えます)。リストを一度調べて、特定の述語に一致する要素を数えるだけです。
この機能を実現するには、fold 関数の 1 つを使用できます。ほとんどの場合、foldl を使用するのが理にかなっています。これは、リストを左から右に末尾再帰的にトラバースするためです。

fun p (x, y) = if y > 2*x then 1 else 0

fun f [] = 0
  | f (x::xs) = foldl (fn (a,b) => b + p(x, a)) 0 xs
于 2013-04-25T14:07:33.757 に答える
2

この解決策を試してください:

fun find lst =
    case lst of
        [] => 0
      | x::_ => List.length(List.filter(fn e => e > 2 * x) lst)

使用法:

find [3,3,4,5,6,7,8,9,11] => 4
于 2013-04-25T10:02:52.793 に答える