2011-09-13 4 views
10

が起こっている私は、クラウドHaskellのパッケージのEncoding.hsを見ている、と私は、誰かが私をよりよく理解するのに役立つ可能性が期待していたいくつかの奇妙なコードに遭遇しています。必要なコードが含まれています:Haskellの魔法のコード、何がここ

class (Binary a,Typeable a) => Serializable a 
instance (Binary a,Typeable a) => Serializable a 

data Payload = Payload 
    { 
     payloadType :: !ByteString, 
     payloadContent :: !ByteString 
    } deriving (Typeable) 

serialDecodePure :: (Serializable a) => Payload -> Maybe a 
serialDecodePure a = (\id -> 
    let pc = payloadContent a 
    in pc `seq` 
     if (decode $! payloadType a) == show (typeOf $ id undefined) 
     then Just (id $! decode pc) 
     else Nothing) id 

私はちょうど$! (私はちょうど厳密に評価していると推測しています)、なぜidトリックが必要なのでしょうか?また、私は特にこのラインに問題が生じています:

if (decode $! payloadType a) == show (typeOf $ id undefined) 

私はこれを推測している、payloadTypeが何らかの理由で無効である場合は見ているが、そのような場合には、その後、他の句を切り替えるべきではありませんすなわち変更:あなたが提供することができます任意の助け

if (decode $! payloadType a) == show (typeOf $ id undefined) 
    then Just (id $! decode pc) 
    else Nothing 

if (decode $! payloadType a) == show (typeOf $ id undefined) 
    then Nothing 
    else Just (id $! decode pc) 

に感謝します。

+0

はい、 'f $! xは厳格なアプリケーションです。厳密性の追加方法について[この記事(http://neilmitchell.blogspot.com/2008/05/bad-strictness.html)]が啓発されているかもしれません。 –

+0

も参照してくださいhttp://stackoverflow.com/q/2787543/246886 –

答えて

12

あなたは$!が厳しい評価者であることを正しいです。型は$と同じですが、唯一の意味の違いは、関数に渡される前に2番目の引数がseq 'であるということです。

私はidは、型推論を助けるためにそこに実際にあると思います。

:これは、このラインによるものであり、機能ブロック (\id -> ...)内では、機能 idaだけで任意の型変数ではないタイプ a -> aを、持っていることを余儀なくされていますが、

serialDecodePure :: (Serializable a) => Payload -> Maybe a 

のよう同じa

Just (id $! decode pc) 

このタイプはMaybe aであるため、idは推測タイプa -> aです。その結果、ライン上であなたはaが再び出力と同じです

if (decode $! payloadType a) == show (typeOf $ id undefined) 

id undefined :: a、見ています。

これで型チェックができました。この関数は多相であるため、型のいずれかにデコードするので、エンコードされたデータがデコードする型と互換性があるかどうかをチェックする必要があります。 Stringをエンコードし、Intにデコードしようとしている場合はどうなりますか? LHSは "[Char]"にデコードします。これはStringのTypeRep表現です。 RHSは、代わりにデコードしようとしている「Int」になります。それらは等しくないので、 "else"パスはNoneを返すパスです。

このid関数の種類の制限ではなく、ScopedTypeVariablesという拡張子で同じことを達成できます。

+1

オハイオ州の男は、idのものは方法賢いです –

4

うわー、これは奇妙なコードですよ!

f $! x = x `seq` f x 

idトリックはsneakierであり、すべての種類の制限についてです:あなたが推測として、($!)は厳しさについてです。関数本体でidが2回使用されていることがわかります。 2回目はid $! decode pcとして使用されます。これはタイプdecodeがどんなものでも動作するようにidのタイプを修正します。最初の使用はtypeOf $! id undefinedです。 idのタイプはすでに修正されているので、単形引数に適用されます(あなたは「あいまいなタイプ」のエラーを得ることはありません)typeOfように、これは、undefinedの種類を修正します。この種のことは、このトリッキーではなく、ScopedTypeVariablesという拡張子で行われることがよくありますが、可能な限り拡張機能を避けたいと思ったのかもしれません。この意味について:

(decode $! payloadType a) == show (typeOf $ id undefined) 

...それはそのように私には見えますが、ペイロードがthenブランチにdecodeへの呼び出しによって返されたものの型と一致していることを確認しています。一致するとJustの値(つまり成功)、そうでない場合はNothingの値(失敗)があると考えられます。

関連する問題