gpt4 book ai didi

haskell - 将函数与 Haskell 中的类型相关联

转载 作者:行者123 更新时间:2023-12-02 01:34:16 25 4
gpt4 key购买 nike

假设你有一个序列化器/反序列化器类型类

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 不允许其他更简单的解决方案时需要它们,但现在不应再使用它们。
现代方法是打开无害的扩展 AllowAmbiguousTypesTypeApplications并简单地写你想要的类(class)
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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com