その引数を自分自身に適用する関数?

次のSML関数を考えてみましょう。

fn x => x x

これにより、次のエラーが発生します(Standard ML of New Jersey v110.72)。

stdIn:1.9-1.12 Error: operator is not a function [circularity]
  operator: 'Z
  in expression:
    x x

私は、これが許されない理由を見てみることができます。一つは、そのタイプが何であるかを書き留める方法は本当に分かりませんが、それは完全に無意味ではありません。たとえば、アイデンティティ関数を渡して戻すことができます。

この関数の名前はありますか? (SMLで表現する方法はありますか?)

7
私はそれがUコンビネータと呼ばれていたことは知らなかったが、そのページが述べているように、それは私の答えに入れたタイプのないラムダ計算の(終わりはない)プログラムを構築するのに使われている。
追加された 著者 Fred Foo,
もし誰かが興味があれば、これは U Combinator(ページの下部を参照)と呼ばれていましたが、それについてもっと多くを見つける。
追加された 著者 Ismail Badawi,

2 答え

There is no way to express this function in a language with an ML-like type system. Even with the identity function it wouldn't work, because the first x and the second in x x would have to be different instances of that function, of type (_a -> _a) -> (_a -> _a) and _a -> _a, respectively, for some type _a.

実際、タイプシステムは次のような構造を禁止するように設計されています。

(λx . x x) (λx . x x)

タイプのないラムダ計算で。動的に型付けされた言語Schemeでは、この関数を書くことができます:

(define (apply-to-self x) (x x))

期待される結果を得る

> (define (id x) x)
> (eq? (apply-to-self id) id)
#t
7
追加された
例えば、私はジェネリック関数の異なる具体的なタイプのインスタンス化を意味します。
追加された 著者 Fred Foo,
"x xの最初のxと2番目の部分はその関数の異なるインスタンスでなければならないからです":好奇心から怠惰な評価を持つ言語はどうですか?それに加えて、SMLに「インスタンス」のようなものがあるかどうかはわかりません(ただし、副作用がある場合を除く)。問題はタイピングの問題です(タイプではなく、しばしば意味をなさないが、必ずしもそうではない)。
追加された 著者 Hibou57,

このような関数は固定小数点コンビネータでしばしば遭遇します。例えば Yコンビネータの1つの形式はλf。(λx.f (xx))(λx.f(xx))固定小数点コンビネータは、追加の再帰的な構造を持たないタイプ化されていないラムダ計算で一般的な再帰を実装するために使用され、これはタイプ変換されていないラムダ計算チューリング完了の一部です。

ラムダ計算の上に単純な静的型システムである単純型ラムダ計算法を開発したときそのような機能を書くことがもはや不可能であることを発見しました。実際、単純型のラムダ計算では一般的な再帰を実行することはできません。したがって、単純型のラムダ計算はもはやチューリング完全ではない。 (興味深い副作用の1つは、単純型のラムダ計算のプログラムは常に終了することです)。

Standard MLのような実際の静的型プログラミング言語には、名前付き再帰関数( val rec または fun で定義)や再帰的な名前付きデータ型。

再帰的なデータ型を使用して、必要なものをシミュレートすることは可能ですが、それほど美しくはありません。

Basically, you want to define a type like 'a foo = 'a foo -> 'a; however, this is not allowed. You instead wrap it in a datatype: datatype 'a foo = Wrap of ('a foo -> 'a);

datatype 'a foo = Wrap of ('a foo -> 'a);
fun unwrap (Wrap x) = x;

Basically, Wrap and unwrap are used to transform between 'a foo and 'a foo -> 'a, and vice versa.

xx の代わりに関数を呼び出す必要がある場合は、(unwrap x)x (または unwrap xx ) ;つまり、 unwrap は元の値に適用できる関数に変換します。

P.S. Another ML language, OCaml, has an option to enable recursive types (normally disabled); if you run the interpreter or compiler with the -rectypes flag, then it is possible to write things like fun x -> x x. Basically, behind the scenes, the type-checker figures out the places where you need to "wrap" and "unwrap" the recursive type, and then inserts them for you. I am not aware of any Standard ML implementation that has similar recursive types functionality.

4
追加された
「私は、同様の再帰型の機能を持つ標準的なML実装については認識していません.SMLの定義では許可されていないため、これを実装することはありません。それをデータ型で囲む必要があるかもしれません。 'a f =' a f - > 'a のような型定義を見ると、それは書き換えルールか、それ以上の型の評価だと思えます。しかし、私はこれに偏っているかもしれません。
追加された 著者 Hibou57,