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.
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
idis actually there to help type inference. Within the function block(\id -> ...), the functionidis forced to have typea -> a, whereais not just any type variable, but the sameaas inThis is due to this line:
since this has type
Maybe a,idhas the inferred typea -> a. As a consequence, on the line you’re looking at,id undefined :: a, whereais 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
Stringand 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
ScopedTypeVariablesextension.