haskell - 从幻像类型创建(获取)值实例

标签 haskell gadt phantom-types

我正在使用 GADT 创建货币的基本维度(如物理维度)系统。维度(例如美元、美元/欧元、欧元/美元)以虚拟类型表示。 我希望能够以例如以下方式打印一定数量的货币: “10.3USD”或“0EUR”以及汇率,例如使用显示“10.3USD/EUR”。 我不太确定如何解释我的问题,所以我将举一个例子来说明我如何尝试解决它:

{-# LANGUAGE GADTs #-}

class (Show a) => Currency a where unphantom :: a

data USD = USD deriving Show
data EUR = EUR deriving Show

instance Currency USD where unphantom = USD
instance Currency EUR where unphantom = EUR

data Amount a where
  Amount :: Currency a => Float -> Amount a
instance Show (Amount a) where 
  show (Amount x) = show x ++ show (unphantom :: a)

data Rate a b where
  Rate :: (Currency a, Currency b) => Float -> Rate a b
-- ...

使用此代码,我收到错误

$ ghc example.hs 
[1 of 1] Compiling Main             ( example.hs, example.o )

example.hs:14:37:
    Could not deduce (Currency a1) arising from a use of `unphantom'
    from the context (Currency a)
      bound by a pattern with constructor
                 Amount :: forall a. Currency a => Float -> Amount a,
               in an equation for `show'
      at example.hs:14:9-16
    Possible fix:
      add (Currency a1) to the context of
        an expression type signature: a1
        or the data constructor `Amount'
        or the instance declaration
    In the first argument of `show', namely `(unphantom :: a)'
    In the second argument of `(++)', namely `show (unphantom :: a)'
    In the expression: show x ++ show (unphantom :: a)

我必须说,我不明白为什么在这种情况下,当我指定 a 时,编译器正在谈论 a1 类型。

当然,我想避免表示 haskell 类型系统之外的维度,因为这为我添加了额外的样板代码,并且据我所知理论上是不必要的(即编译器应该有足够的信息来推断如何显示编译时的数量或速率)(并在运行时增加一点开销)。

最佳答案

使用ScopedTypeVariables并且您的代码按原样编译。

特别是,没有ScopedTypeVariables当你写的时候

instance Show (Amount a) where 
  show (Amount x) = show x ++ show (unphantom :: a)

aunphantom :: a 新鲜并且未与 a 统一在instance Show (Amount a) where 。正在开启ScopedTypeVariables迫使它统一。

关于haskell - 从幻像类型创建(获取)值实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24985896/

相关文章:

http - 如何使用 wreq 只下载部分响应?

haskell - 构建黑线鳕时如何排除依赖项?

json - 如何使用 Haskell Lens 重写 JSON 结构中的任意嵌套字段?

haskell - 异构 GADT 列表

haskell - 对 GADT 和传播约束感到困惑

haskell - 幽灵类型困惑?

typescript - 如何使幻像类型与 TypeScript 中的方法一起使用?

haskell - 指称语义映射是可判定的吗?

haskell - 如何让 GHC 为上下文中具有 Typeable 的 GADT 生成 Data.Typeable 实例?

haskell - 如何使用 Data Kinds + Phantom types 对 Haskell 中的单元进行编码?