使用类型族来避免MPTC中的显式类型参数

Dan*_*rro 4 haskell type-families

我想知道是否有任何方法(可能使用Type Families)Buildable使用build方法定义类型类,以便这样的东西可以工作:

>>> import qualified Data.ByteString.Builder as B (Builder)
>>> import qualified Data.Text.Lazy.Builder as T (Builder)

>>> -- This should internally use `int8` from `Data.ByteString.Builder`:
>>> build (8::Int8) :: B.Builder

>>> -- This should internally use `decimal` from `Data.Text.Lazy.Builder`:
>>> build (8::Int8) :: T.Builder

>>> -- If no concrete type is specified, I'd expect something like this:
>>> :t build (8::Int8)
GBuilder Int8
Run Code Online (Sandbox Code Playgroud)

我知道如何使它与MPTC一起工作,但我必须明确定义要构建的值的类型和构建器的类型.有没有办法让类型系统自动选择预期的类型而不显式传递它?

Nik*_*kov 5

嗯,明显的解决方案如下:

class Builder b where
  type Element b
  build :: Element b -> b

instance Builder B.Builder where
  type Element B.Builder = Int8
  build = B.int8

instance Builder T.Builder where
  type Element T.Builder = Int8
  build = T.decimal
Run Code Online (Sandbox Code Playgroud)

但是,这个问题是类型族不能用于确定实例.所以在这种情况下,实例只能由bfrom 确定build :: Element b -> b,而不能由from 确定Element b.在处理类型检查错误时,这很有用.

由于我刚才提到的很多情况,只能使用数据系列.标准方法是提供newtype包装器.例如:

class Builder b where
  data Element b
  build :: Element b -> b

instance Builder B.Builder where
  newtype Element B.Builder = BElement Int8
  build (BElement a) = B.int8 a
Run Code Online (Sandbox Code Playgroud)

在这种情况下,实例可以从两个来确定bElement bbuild :: Element b -> b.

  • 我正要问如何将其扩展为`Int16`,`Word8`等...但是通过向关联数据类型添加更多构造函数可以实现:`data Element B.Builder = BElementInt8 Int8 | BElementInt16 Int16 ...`.如果有人有同样的问题,我会把它写成评论. (2认同)