2013-04-16 11 views
7

私はこれを読んできましたhttp://www.haskell.org/haskellwiki/Hask。私は評価中 _ - > Haskellで未定義

undef1 = undefined :: a -> b 
undef2 = \_ -> undefined 

そして、なぜ彼らがこのように振る舞う...この部分で苦労しています。..

seq undef1() = undefined 
seq undef2() =() 
undef2() = undefined 

をその理由は何ですか?私はこの行動を理解したいと思っていますが、どこから始めたらいいのか分かりません。特に、厳密な評価のもとでundef2の動作が異なるのはなぜですか?

答えて

9

特殊関数seqは、弱い頭部標準形の第1引数を評価し、次に第2引数を返します。 WHNFの良い説明がhereを見つけることができますが、この回答の目的のために、私はちょうど使用しますHaskell wiki definition

式が、それはどちらかだ場合、弱い頭部正規形(WHNF)である:

  • (+)2やsqrtのように引数が少なすぎる(おそらくnone)関数が適用されます(最終的には引数に適用されます)。
  • またはラムダ抽象化\ x - >式です。

重要な点は、式がコンストラクタであるとき、seqだけコンストラクタのタグを見ていることです。したがって、seq (Just undefined) 11と評価されます。つまり、型の値を評価すること(通常error又はundefinedで)実行されるか、例外がスローされる無限ループにつながる可能性が -

別の重要な点は、Haskellの中のすべてのタイプがliftedであるということです。 seq a bを評価した後、aからWHNFを評価しても、無限ループまたは例外が発生することはありません。この知識で武装し

、のはあなたの例を見てみましょう:

undef1 = undefined :: a -> b 
undef2 = \_ -> undefined 

seq undef1()が評価され、seq最初の試みが属するundef1上記の3つのカテゴリのどれを見つけるために。しかしundef1undefinedなので、全体の表現はundefinedと評価されます。

しかし、seq undef2() =()の場合には、最初の引数はラムダ抽象化です。 seqはラムダを過ぎて見ることができないので、2番目の引数を返します。

第3の例のundef2() = undefinedは、アプリケーション(\_ -> undefined)()を評価した単純な結果です。

+0

優れています。ありがとうございました。 Hehe、ええ、 – user21154

3

これらは同じものではありません。 undef1はaからbまでの関数ですが、関数は未定義です。 undef1 to head normal formを評価すると、未定義となります。

undef2はaからbの関数です。具体的には、引数を無視して未定義を返す関数です。しかし、undef2自体は未定義ではありません。関数を評価しようとするとき(3行目のように)のみ、あなたは未定義になります。だから、undef2を評価して普通の形にするときは、未定義ではなく、適切な関数が得られます。

より絶対的な言葉(常に不正確な情報源ですが、それに精通していれば、その点をうまく示しています)には、undef1を決して返さないプロパティゲッターと考えてください。 (ハスケルでは、返されず、未定義は意味的に同等です。)undef2は、関数を返すプロパティゲッターです。それを呼び出すと返されない関数です。 C#の場合:

Func<Object, Object> Undef1 { 
    get { 
    while (true) {} 
    return null; 
    } 
} 

Func<Object, Object> Undef2 { 
    get { 
    return _ -> { 
     while (true) {} 
     return null; 
    } 
    } 
} 

今、あなたのテストは次のようになります。

var x = Undef1; 
var y = Undef2; 
var z = Undef2(null); 
3

この質問のために、のは実際に評価される値を強制することができる3つのものがあるとしましょう:

  • その値でのパターンマッチング
  • 引数への値の適用
  • それを最初の引数として使用するseq

実際の状況は少し複雑ですが、ここでは重要ではありません。

さらに、この強制は一部の外部式のコンテキストでのみ発生するため、これらを「抽象的な方法で強制的に評価する」と考えるのではなく、外部式の評価をその価値の評価これは、例えば、seq x xが強制的にxを強制しない理由です。なぜなら、それはとにかく式の最終的な値なのですから。外側の式(値がx)が評価されるとき、それは冗長であるxも評価する必要があります。

最後に、未定義の値を強制することに依存する値自体は、未定義です。


各式を通って行く:

seq undef1() = undefined 

この場合undef1では未定義であり、そしてseq undef1 xは、その値xあり、undef1の評価に依存する式です。したがって、seqの第2引数が何であるとしても、式全体は未定義です。この場合

seq undef2() =() 

undef2不定、それをされている適用した結果ありません。 seq undef2 xは、値がxの式であり、評価結果はundef2です。これにより問題は発生せず、seqの最初の引数は破棄されるため、式の値は()になります。

undef2() = undefined 

この場合、undef2を直接適用しています。式undef2()は、undef2(これは問題ありません)の評価に依存し、の適用結果(この場合はundefined)と評価されます。第4のケースと

コントラストこの:式の値は未定義ですundef1を、評価に依存し、したがって、その式全体であるので、この場合は

undef1() = undefined 

は、我々は、undef1を適用しています。これは前の式と同じ "値"です。undef2を使用していますが、非常に異なる理由があります。

3

f xのような式の評価を強制するためには、まずHaskellは何の機能を理解する必要がありますか?xを適用してください。より専門的に言えば、f xの場合は、に強制されます。fを強制する必要があります。

は、今度は戻ってあなたの定義に行こう:

undef1を強制
undef1 :: a -> b 
undef1 = undefined 

undef2 :: a -> b 
undef2 = \_ -> undefined 

undef2は異なる結果を生成します。 undef1はすぐにundefinedを生成しますが、強制的にundef2を生成すると、何らかの引数に適用するとundefinedが生成されます。

seqが誤解していると思われます。 seq undef2()undef2()に適用すると思われる印象を受けますが、そうではありません。 seq :: a -> b -> bが行うことは、最初の引数を強制して2番目の引数を返すことです。 seq undef1()seq undef2()の違いは、最初の引数を強制するときに2番目のものだけが成功するが、その後は単に()が返されるということだけです。

私が上記のコードであなたの意図について正しいのであれば、あなたが探しているのは($!) :: (a -> b) -> a -> bです。これは最初の引数を2番目の引数に適用し、結果を強制します。したがって、これらの両方は、undefinedで失敗します。

undef1 $!() 
undef2 $!() 
+0

私は認めなければなりません。私はseqで完全に明確ではなかった。ありがとう。 – user21154

関連する問題