14

Jason Hickey の Introduction to Objective Caml を学んでいます。


これは私が手がかりを持っていない演習です

ここに画像の説明を入力 ここに画像の説明を入力


dictionaryまず、を として実装するとはどういう意味functionですか? どうすればそれをイメージできますか?

そのようなものは必要arrayですか?どうやら、この演習では配列を使用できないようです。なぜなら、arrayはまだ導入されていないからChapter 3です。しかしHow do I do it without some storage?

どうすればいいのかわからないので、ヒントやガイドをお願いします。

4

4 に答える 4

10

この演習のポイントは、クロージャーを使用できるようにすることだと思います。たとえば、ファイル内の次の OCaml 関数のペアを考えてみましょうfun-dict.ml:

let empty (_ : string) : int = 0
let add d k v = fun k' -> if k = k' then v else d k'

次に、OCaml プロンプトで次の操作を実行できます。


# #use "fun-dict.ml";;
val empty : string -> int = 
val add : ('a -> 'b) -> 'a -> 'b -> 'a -> 'b = 
# let d = add empty "foo" 10;;
val d : string -> int = 
# d "bar";;  (* Since our dictionary is a function we simply call with a
                  string to look up a value *)
- : int = 0   (* We never added "bar" so we get 0 *)
# d "foo";;
- : int = 10  (* We added "foo" -> 10 *)

この例では、ディクショナリは値に対するstringキーの関数intです。このempty関数は、すべてのキーを にマップする辞書です0。add 関数は、1 つの引数 (キー) を取るクロージャを作成します。ここでのディクショナリの定義は、キーから値への関数であるため、このクロージャはディクショナリです。k'(クロージャーパラメーター) が追加されたばかりのキーが= kどこにあるかを確認します。k存在する場合は新しい値を返し、そうでない場合は古い辞書を呼び出します。

チェーン内の次の辞書(関数)を閉じることにより、コンスセルではなくチェーンされたクロージャーのリストを効果的に持っています)。

余分な演習ですが、この辞書からキーを削除するにはどうすればよいですか?


編集:閉鎖とは何ですか?

クロージャは、それが作成されたスコープから変数 (名前) を参照する関数です。では、それはどういう意味ですか?

add私たちの機能を考えてみましょう。関数を返します

fun k' -> if k = k' then v else d k

その関数だけを見ると、定義されていないdk、およびの 3 つの名前がありvます。それらが何であるかを理解するには、囲んでいるスコープ、つまり のスコープを調べる必要がありaddます。私たちが見つけた場所

let add d k v = ...

そのため、新しい関数が返された後でも、addその関数は追加する引数を引き続き参照します。したがって、クロージャーは、意味を持つために何らかの外部スコープによって閉じられなければならない関数です。

于 2012-12-04T18:31:09.270 に答える
7

OCaml では、実際の関数を使用して辞書を表すことができます。通常、非 FP 言語はファーストクラス オブジェクトとしての関数をサポートしていないため、慣れていると最初はそのように考えるのに苦労するかもしれません。

辞書関数であるマップです。d文字列を受け取って数値を返す関数があるとします。異なる文字列に対して異なる数値を返しますが、同じ文字列に対して常に同じ数値を返します。これは辞書です。文字列は検索対象であり、返される数値は辞書内の関連するエントリです。

配列 (またはリスト) は必要ありません。関数addは、(明示的な) データ構造なしで必要なことを行う関数を構築できます。addこの関数は辞書 (関数) を取り、辞書 (新しい関数) を返すことに注意してください。

高階関数について考え始めるために、ここに例を示します。この関数bumpは、関数 ( f: int -> int) と int ( ) を取りますk: int。同じ入力に対して返される値kよりも大きい値を返す新しい関数を返します。f

let bump f k = fun n -> k + f n

(ポイントは、 がbumpと同様addに、関数といくつかのデータを受け取り、これらの値に基づいて新しい関数を返すことです。)

于 2012-12-04T17:46:53.027 に答える
5

OCamlの関数は単なるコードではないことを付け加える価値があると思いました(C、C ++、Javaなどとは異なります)。それらの非関数型言語では、関数にはそれらに関連付けられた状態がありません。そのようなことについて話すのはちょっとばかげているでしょう。しかし、これは関数型言語の関数には当てはまりません。それらを一種のオブジェクトと考え始める必要があります。奇妙な種類のオブジェクト、はい。

では、どうすればこれらのオブジェクトを「作成」できるでしょうか。ジェフリーの例を見てみましょう:

let bump f k = 
  fun n ->
    k + f n

さて、bump実際には何をしますか?すでに慣れ親しんでいるコンストラクターbumpとして考えると役立つ場合があります。それは何を構築しますか?関数オブジェクトを構築します(ここでは非常にわかりにくいです)。では、その結果のオブジェクトはどのような状態になりますか?とである2つのインスタンス変数(一種)があります。これらの2つのインスタンス変数は、を呼び出すと、結果の関数オブジェクトにバインドされます。返された関数オブジェクトが次のようになっていることがわかります。fkbump f k

fun n ->
  k + f n

これらのインスタンス変数fkその本体を利用します。この関数オブジェクトが返されると、それを呼び出すことしかできず、fまたはにアクセスする他の方法はありませんk(したがって、これはカプセル化です)。

関数オブジェクトという用語を使用することは非常にまれです。これらは単に関数と呼ばれますが、状態を「囲む」こともできることに注意する必要があります。これらの関数オブジェクト(クロージャとも呼ばれます)は、オブジェクト指向プログラミング言語の「実際の」オブジェクトからそれほど離れていません。非常に興味深い議論がここにあります。

于 2012-12-04T21:39:35.940 に答える
1

私もこの問題に苦しんでいます。これが私の解決策であり、教科書に記載されているケースで機能します...

空の辞書は単に 0 を返します:

let empty (k:string) = 0

Find はキーで辞書の関数を呼び出します。この関数は簡単です:

let find (d: string -> int) k = d k

Add は、ディクショナリの機能を拡張して、別の条件分岐を持つようにします。キー k' を取り、それを k (追加する必要があるキー) と照合する新しい辞書を返します。一致する場合は、v (対応する値) を返します。一致しない場合は、古い (小さい) 辞書を返します。

let add (d: string -> int) k v =
    fun k' ->
        if k' = k then
                v
            else
                d k'

add を変更して remove 関数を持たせることができます。また、存在しないキーを削除しないようにする条件を追加しました。これは練習用です。とにかく、辞書のこの実装は悪いです:

let remove (d: string -> int) k =
    if find d k = 0 then
        d
    else
        fun k' ->
            if k' = k then
                    0
                else
                    d k'

私はまだ関数型プログラミングを学んでいるので、用語が苦手です。だから、お気軽に私を修正してください。

于 2013-02-05T11:54:45.703 に答える