假设您有一个序列化器/反序列化器类型类
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
事实证明,为每种类型的a
(例如,compress :: ByteString -> ByteString -- actually varies with the original type
我将compress
视为要与每个a
的SerDes
关联的函数。 (“关联”一词可能是一个错误的选择,也是互联网搜索无法产生任何结果的原因。)该示例并不像它看起来的那样虚构,例如当
decompress
是可选的时串行器/解串器的功能。 (是的,可以通过增加
ser
,带有一个控制压缩的开关ser:: a -> Bool -> ByteString
,或者最好使用Config
记录。但是让我们坚持这个例子。)一种实现方式是“虚拟”类,即单例:
data For a = For
然后这将起作用:class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: For a -> ByteString -> ByteString
并将compress
的a
实例化为compress (For :: For MyType) input = ...
另一种不同寻常的方法是将所有功能记录在案。data SerDes a = SerDes { ser :: a -> ByteString
, des :: ByteString -> a
, compress :: ByteString -> ByteString
}
还有其他方法可以将compress
函数与a
类型“关联”吗? 最佳答案
您的For a
类型在库中称为Proxy a
。
import Data.Proxy
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: Proxy a -> ByteString -> ByteString
有时,将其概括为通用的proxy
类型变量。class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: proxy a -> ByteString -> ByteString
还有另一种选择,类似于代理。除了强制将
a
添加到参数之外,还可以使用a
将Tagged
添加到结果类型:import Data.Tagged
class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: ByteString -> Tagged a ByteString
这需要用作unTagged (compress someByteString :: Tagged T ByteString)
来告诉编译器我们想要compress
的T
函数。就个人而言,我不喜欢代理和标签。过去,GHC不允许使用其他更简单的解决方案时就需要使用它们,但是现在不应该再使用它们。
现代的方法是打开无害扩展
AllowAmbiguousTypes
和TypeApplications
并简单地编写所需的类class SerDes a where
ser :: a -> ByteString
des :: ByteString -> a
compress :: ByteString -> ByteString
在这种方法中,代替调用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
关于haskell - 将函数与Haskell中的类型相关联,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63667281/