我正在使用GADT为货币创建基本尺寸(如物理尺寸)系统。维度(例如USD,USD / EUR,EUR / USD)表示为幻像类型。
我希望能够以例如“ 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)


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

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

最佳答案

使用ScopedTypeVariables,您的代码将按原样编译。

特别是在编写时不使用ScopedTypeVariables

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


a中的unphantom :: a是新鲜的,并且不能与a中的instance Show (Amount a) where统一。启用ScopedTypeVariables强制将其统一。

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

10-11 17:41