haskell神奇的代码,这是怎么回事
我正在查看 Cloud Haskell 包的 Encoding.hs,并遇到了一些奇怪的代码,我希望有人可以帮助我更好地理解。包括必要的代码:
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 是否因任何原因无效,但如果是这种情况,则不应切换 then 和 else 子句,即更改:
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)
感谢任何您可以提供的帮助。
I'm looking over the Cloud Haskell package's Encoding.hs, and encountered some strange code that I was hoping someone could help me better understand. Included is the necessary code:
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
I'm just curious about what the $! does (I'm guessing just strictly evaluates), and also why we need the id trick (something with lazy evaluation?). Also I am specifically having problems with this line:
if (decode $! payloadType a) == show (typeOf $ id undefined)
I'm guessing this is seeing if the payloadType is invalid for whatever reason, but if that is the case shouldn't the then and else clauses be switched, ie change:
if (decode $! payloadType a) == show (typeOf $ id undefined)
then Just (id $! decode pc)
else Nothing
to
if (decode $! payloadType a) == show (typeOf $ id undefined)
then Nothing
else Just (id $! decode pc)
Thanks for any help you can provide.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您是对的,
$!
是一个严格的求值器。它的类型与$
相同,唯一的语义差异是第二个参数在传递给函数之前经过seq
处理。我认为 id 实际上是为了帮助类型推断。在功能块
(\id -> ...)
中,函数id
被强制具有类型a -> a
,其中a
不仅仅是任何类型变量,而是与 This 中相同的a
,这一行:
这是由于 this 的类型为
Maybe a
,id
的推断类型为a ->;一个。因此,在您正在查看的行上,
id undefined :: a
,其中a
再次与输出相同。现在我们可以进行类型检查了。由于此函数是多态的并且将解码为任何类型,因此它需要检查编码数据是否与其解码的类型兼容。如果您对
String
进行编码并尝试解码为Int
该怎么办? LHS 将解码为“[Char]”,这是字符串的 TypeRep 表示形式。 RHS 将改为“Int”,即它尝试解码的类型。由于它们不相等,因此“else”路径是返回None
的路径。您可以使用 ScopedTypeVariables 扩展来完成相同的操作,而不是使用此 id 函数类型限制。
You are correct that
$!
is a strict evaluator. It's type is identical to$
, and the only semantic difference is that the second argument isseq
'd before being passed to the function.I think the
id
is actually there to help type inference. Within the function block(\id -> ...)
, the functionid
is forced to have typea -> a
, wherea
is not just any type variable, but the samea
as inThis is due to this line:
since this has type
Maybe a
,id
has the inferred typea -> a
. As a consequence, on the line you're looking at,id undefined :: a
, wherea
is again the same as the output.Now we can get to the type checking. Since this function is polymorphic and will decode to any type, it needs to check that the encoded data is compatible with the type it's decoding to. What if you encoded a
String
and are trying to decode to anInt
? The LHS would decode to "[Char]", which is the TypeRep representation of a String. The RHS would instead be "Int", the type it's attempting to decode to. Since they aren't equal, the "else" path is the one that returnsNone
.Rather than this id function type restriction, you could accomplish the same thing with the
ScopedTypeVariables
extension.哇,这是一些看起来很奇怪的代码!正如您所猜测的,
($!)
是关于严格性的:id
技巧更加狡猾,并且完全与类型限制有关。您会注意到id
在函数体中使用了两次。第二次它被用作id $!解码电脑
;这修复了id
的类型,以对decode
输出的任何类型的内容进行操作。第一次使用是typeOf $! id 未定义
;由于id
的类型已经被修复,这修复了undefined
的类型,因此typeOf
被应用于单态参数(并且你不要出现“类型不明确”错误)。这种事情通常是使用 ScopedTypeVariables 扩展而不是这种技巧来完成的,但也许他们希望尽可能避免扩展。至于它的含义:...在我看来,这是在检查有效负载是否与
then
中调用decode
返回的内容的类型相匹配分支。当它们匹配时,拥有Just
值(即成功),而当它们不匹配时,拥有Nothing
值(即失败)似乎是有意义的。Wow, that's some weird-looking code! As you guessed,
($!)
is about strictness:The
id
trick is sneakier, and is all about type restriction. You'll notice thatid
is used twice in the function body. The second time it's used asid $! decode pc
; this fixes the type ofid
to operate on whatever kind of thingdecode
outputs. The first use is astypeOf $! id undefined
; since the type ofid
has been fixed already, this fixes the type ofundefined
, so thattypeOf
is applied to a monomorphic argument (and you don't get "ambiguous type" errors). This kind of thing is often done with theScopedTypeVariables
extension instead of this trickery, but perhaps they wanted to avoid extensions wherever possible. As for the meaning of this:...it looks to me like that is checking that the payload matches the type of the thing returned by the call to
decode
in thethen
branch. It seems to make sense to have aJust
value (i.e. success) when they match, and aNothing
value (i.e. failure) when they don't.