4

次のコードがあるとします。

let DisplayImpl logger data =
    data |> Seq.iter logger
    printfn ""

let Working =
    DisplayImpl (printfn "%O") [1;2;3]
    DisplayImpl (printfn "%O") ["a";"b";"c"]

let NotWorking display =
    display (printfn "%O") [1;2;3]
    display (printfn "%O") ["a";"b";"c"]
                            ~~~ ~~~ ~~~

最後の行で次のエラーが表示されます。This expression was expected to have type int but here has type string

私は次のことがうまくいくかもしれないと思ったが、うまくいかない:

let StillNotWorking (display: ('a -> unit) -> seq<'a> -> unit) =

私の質問は、表示パラメーターが関数内で汎用的なままになるように NotWorking 関数を定義するにはどうすればよいですか?

4

2 に答える 2

6

引数として他の関数 ( などdisplay) に渡される関数は、F# でそれ自体を多態的にすることはできません。ジェネリック型パラメーター ('aなど) を使用できますが、このパラメーターの実際の型は、メイン関数 (このNotWorking場合) が呼び出されるときに指定されます。これは、本体のdisplay型変数に使用される単一の実際の型でのみ呼び出すことができることを意味します。'aNotWorking

回避策として、ジェネリック メソッドでインターフェイスを使用できます。

type Displayer = 
  abstract Display : (obj -> unit) -> 'T list -> unit
 
let NotWorking (display:Displayer) = 
    display.Display (printfn "%O") [1;2;3] 
    display.Display (printfn "%O") ["a";"b";"c"] 

インターフェイスのメソッドDisplayはそれ自体がジェネリック メソッドであるため、そのメソッドを異なる型引数で複数回呼び出すことができます (int最初のケースとstring2 番目のケース)。

ただし、F#で通常のコードを頻繁に記述する場合、これが制限であるとは思いませんでした。そのため、問題に対するより簡単な解決策があるかもしれません(おそらく、非ジェネリックIEnumerableまたはそのような単純なものを使用する-またはobj listJohnからの回答のように) )。実際のコードの詳細を教えていただけると助かります。

理論的な詳細に興味がある場合に備えて、いくつかの背景を説明しますが、これらはどれも、日常の実際の F# プログラミングで重要になるものではありません。ともかく -

これは Haskell のような他の言語で可能であり、それを可能にするメカニズムはユニバーサル タイプと呼ばれます。F# にポリモーフィック関数がある場合、それは基本的に、型変数のスコープが関数全体であることを意味するため('a -> unit) -> unitforall 'a . ('a -> unit) -> unit.

関数を呼び出すときは、'a変更できないものと変更できないものを指定する必要があります (つまり、一度'a -> unitに 2 つの異なる型を引数として取得した関数を使用することはできません)。'a'a

ユニバーサル型を使用するforallと、自分で書くことができるので、その型は: であると言えます
(forall 'a . 'a -> unit) -> unit。これで、ジェネリック パラメーター'aは、引数として取得する関数にのみリンクされます。引数として指定された関数の型は、それ自体が汎用関数になったため、 を表すさまざまな型で呼び出すことができます'a

PS: 値の制限は別の問題です。つまり、基本的に、F# は構文関数ではないものをジェネリックにすることはできませんが、この例では構文関数を記述しているため、ここでは問題になりません。

于 2011-12-08T01:12:41.710 に答える
5

これも同様に機能します

let NotWorking (display:(obj -> unit) -> obj list -> unit) =
    display (printfn "%O") [1;2;3]
    display (printfn "%O") ["a";"b";"c"]
于 2011-12-08T01:20:11.740 に答える