mcm*_*yer 15 haskell record typeclass
假设您有一个序列化器/反序列化器类型类
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
Run Code Online (Sandbox Code Playgroud)
事实证明,对于每种类型都有一个特殊的辅助函数是至关重要的a,例如
compress :: ByteString -> ByteString -- actually varies with the original type
Run Code Online (Sandbox Code Playgroud)
我认为compress作为一个功能,我想每个关联a这是一个SerDes。(“associate”这个词可能是一个糟糕的选择,这也是互联网搜索一无所获的原因。)
该示例并不像看起来那样做作,例如何时decompress是串行器/解串器的可选功能。(是的,可以通过增加ser控制压缩的开关来避免使用助手
ser:: a -> Bool -> ByteString,或者更好地使用Config记录。但让我们坚持这个例子。)
一种方法是一个“虚拟”类,一个单例:
data For a = For
Run Code Online (Sandbox Code Playgroud)
然后这将起作用:
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: For a -> ByteString -> ByteString
Run Code Online (Sandbox Code Playgroud)
并且compressfora将被实例化为
compress (For :: For MyType) input = ...
Run Code Online (Sandbox Code Playgroud)
另一种有点不寻常的方法是将所有功能都保存在一个记录中。
data SerDes a = SerDes { ser :: a -> ByteString
, des :: ByteString -> a
, compress :: ByteString -> ByteString
}
Run Code Online (Sandbox Code Playgroud)
还有其他方法可以将compress函数与类型“关联”a吗?
chi*_*chi 20
您的For a类型Proxy a在库中被称为。
import Data.Proxy
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: Proxy a -> ByteString -> ByteString
Run Code Online (Sandbox Code Playgroud)
有时这被推广到泛型proxy类型变量。
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: proxy a -> ByteString -> ByteString
Run Code Online (Sandbox Code Playgroud)
还有另一种选择,类似于代理。a可以a使用Tagged以下命令添加到结果类型,而不是强行添加到参数中:
import Data.Tagged
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: ByteString -> Tagged a ByteString
Run Code Online (Sandbox Code Playgroud)
这需要用来unTagged (compress someByteString :: Tagged T ByteString)告诉编译器我们想要compress函数T。
就个人而言,我不喜欢代理和标签。过去 GHC 不允许使用其他更简单的解决方案时需要它们,但现在不应再使用它们。
现代方法是打开无害的扩展AllowAmbiguousTypes,TypeApplications然后简单地编写你想要的类
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: ByteString -> ByteString
Run Code Online (Sandbox Code Playgroud)
在这种方法中,compress (Proxy :: Proxy T) someByteString我们需要compress @T someByteString在明确“传递a我们想要的类型”(T在这种情况下)的地方使用较短的而不是调用,以便选择想要的compress.
完整示例:
{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, OverloadedStrings #-}
import Data.ByteString as BS
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: ByteString -> ByteString
-- bogus implementation to show everything type checks
instance SerDes Int where
ser _ = "int"
des _ = 42
compress bs = BS.tail bs
-- bogus implementation to show everything type checks
instance SerDes Bool where
ser _ = "bool"
des _ = True
compress bs = bs <> bs
main :: IO ()
main = BS.putStrLn (compress @Int "hello" <> compress @Bool "world")
-- output: elloworldworld
Run Code Online (Sandbox Code Playgroud)