web-dev-qa-db-ja.com

Haskellおよび/またはラムダ計算におけるパラメーターなしのラムダ式

SchemeやPythonのような熱心な言語では、パラメータなしでラムダ式を使用して評価を遅らせることができます。スキーム(チキンスキーム):

_#;1> (define (make-thunk x) (lambda () (+ x 1)))
#;2> (define t (make-thunk 1))
#;3> (t)
2
_

2行目で、tは未評価の式_(lambda () (+ 1 1))_にバインドされ、3行目で_2_に評価されます。

同様に、Pythonでは:

_>>> def make_thunk(x): return lambda: x + 1
... 
>>> t = make_thunk(1)
>>> t()
2
_

この手法を使用すると、熱心な言語で遅延評価を実装できます。

そのため、言語が既に遅延しており、遅延式を作成する必要がないため、Haskellにはパラメーターなしのラムダ式がないと予想していました。驚いたことに、Haskellではラムダ式を書くことが可能であることがわかりました

_\() -> "s"
_

これは、_()_値にのみ適用できます。

_(\() -> "s") ()
_

結果を出す

_"s"
_

この関数を_()_以外の引数に適用すると、例外がスローされます(少なくとも、テスト中に確認できる限り)。これは、SchemeやPythonでの遅延評価とは異なります。これは、式を評価するために引数が必要なためです。では、変数なしのラムダ式(\() -> "s"など)はHaskellで何を意味し、何のために役立つのでしょうか?

また、同様のパラメーターのないラムダ式が(いくつかの種類の)ラムダ計算に存在するかどうかも知りたいです。

9
Giorgio

さて、他の回答はHaskellでの\() -> "something"の意味をカバーしています:()を引数として取る単項関数です。

  • 引数なしの関数とは何ですか? - 価値。実際、変数をその値に評価されるヌラリ関数と考えると役立つ場合があります。引数のない関数(実際には存在しない)のlet- syntaxは、最終的に変数バインディングを提供します:let x = 42 in ...

  • ラムダ計算にはゼロ関数がありますか? –いいえ。すべての関数は引数を1つだけ受け取ります。ただし、この引数はリストの場合や、関数が次の引数を取る別の関数を返す場合があります。 Haskellは後者のソリューションを好むので、a b cは実際には2つの関数呼び出し((a b) c)になります。 null関数をシミュレートするには、未使用のプレースホルダー値を渡す必要があります。

12
amon

Haskellでの_()_の意味を誤って解釈しています。それは値の不足ではなく、むしろnitタイプのonly値です(タイプ自体は括弧の空のセット_()_)によって参照されます。

ラムダはパターンマッチングを使用するように構築できるため、ラムダ式\() -> "s"は明示的に「無名関数を作成し、_()_パターンに一致する入力を期待する」と言っています。それをする意味はあまりありませんが、それは確かに許可されています。

他の方法でラムダとパターンマッチングを使用することもできます。次に例を示します。

_map (\(a, b) -> a + b) [(1,2), (3,4), (5,6)] -- uses pattern matching to destructured tuples

map (\(Name first _) -> first) [Name "John" "Smith", Name "Jane" "Doe"] -- matches a "Name" data type and its first field

map (\(x:_) -> x) [[1,2,3], [4,5,6]] -- matches the head of a list
_
9
KChaloux

() -> "s"は、one引数を取るラムダ関数です。

ghci> :t (\() -> "s")
(\() -> "s") :: () -> [Char]

空のタプル(Unitとも呼ばれる)である()は、Haskellで本格的な型です。メンバーは1つだけ(_|_ *は無視)であり、()としても記述されます。 ()の定義を見てください。

data () = ()

つまり、ラムダ式の左側のフォームは、()型の唯一のメンバーである()に一致するパターンマッチです。 ()型の有効なメンバーが1つしかないため、それを呼び出す有効な方法は1つだけです(つまり、()を引数として指定します)。

このような関数はHaskellではあまり有用ではありません。質問で確認したように、デフォルトでは用語がとにかく遅延評価されるためです。

より詳細な説明については、 この答え を参照してください。

* _|_は「ボトム」または「未定義」と呼ばれます。常に型チェックを行いますが、プログラムをクラッシュさせます。 _|_を取得する方法の典型的な例は、let x = x in xです。

1