模式匹配幻像类型
Pattern match phantom type
我正在尝试实现一个 CurrencyQty 类型,它的作用类似于在编译时标记的数字:
data Currency = Usd | Eur | Gbp
data CurrencyQty (a :: Currency) = CurrencyQty Double deriving (Num)
现在我想实现一个动态查找汇率的通用转换函数。假设我有一些功能
currentExchangeRate :: Currency -> Currency -> IO Double
我要写
inUsd :: CurrencyQty a -> IO (CurrencyQty Usd)
inUsd (CurrencyQty Usd x) = return x
inUsd (CurrencyQty Eur x) = fmap (*x) $ currentExchangeRate Usd Eur
inUsd (CurrencyQty Gbp x) = fmap (*x) $ currentExchangeRate Usd Gbp
或者不知何故
inUsd :: CurrencyQty a -> IO (CurrencyQty Usd)
inUsd (CurrencyQty a x) = fmap (*x) $ currentExchangeRate Usd a
我使用的语法显然无效haskell...有没有办法做到这一点?
你不能为此使用幻影。 Phantom 类型在运行时消失,您的 inUsd
函数需要一些运行时信息。
通常的方法是使用 GADT 和单例类型。
-- the "index" type
data Currency = Usd | Eur | Gbp
-- the "singleton" type
-- If you want to autogenerate this, check out the singletons
-- package on Hackage
data SCurrency (a :: Currency) where
SUsd :: Scurrency Usd
SEur :: Scurrency Eur
SGbp :: Scurrency Gbp
-- the "indexed" type
data CurrencyQty (a :: Currency) where
CurrencyQty :: SCurrency a -> Double -> CurrencyQty a
instance Num (CurrencyQty a) where
... -- you have to manually write this, I guess?
inUsd :: CurrencyQty a -> IO (CurrencyQty Usd)
inUsd (CurrencyQty SUsd x) = return x
inUsd (CurrencyQty SEur x) = fmap (*x) $ currentExchangeRate Usd Eur
inUsd (CurrencyQty SGbp x) = fmap (*x) $ currentExchangeRate Usd Gbp
让我补充一下,您的代码没问题。如果 Haskell 具有完整的依赖类型,则可以在稍作调整后使用您的代码,并避免使用额外的单例类型。但目前Haskell无法避免,还需要付出更多努力。
我正在尝试实现一个 CurrencyQty 类型,它的作用类似于在编译时标记的数字:
data Currency = Usd | Eur | Gbp
data CurrencyQty (a :: Currency) = CurrencyQty Double deriving (Num)
现在我想实现一个动态查找汇率的通用转换函数。假设我有一些功能
currentExchangeRate :: Currency -> Currency -> IO Double
我要写
inUsd :: CurrencyQty a -> IO (CurrencyQty Usd)
inUsd (CurrencyQty Usd x) = return x
inUsd (CurrencyQty Eur x) = fmap (*x) $ currentExchangeRate Usd Eur
inUsd (CurrencyQty Gbp x) = fmap (*x) $ currentExchangeRate Usd Gbp
或者不知何故
inUsd :: CurrencyQty a -> IO (CurrencyQty Usd)
inUsd (CurrencyQty a x) = fmap (*x) $ currentExchangeRate Usd a
我使用的语法显然无效haskell...有没有办法做到这一点?
你不能为此使用幻影。 Phantom 类型在运行时消失,您的 inUsd
函数需要一些运行时信息。
通常的方法是使用 GADT 和单例类型。
-- the "index" type
data Currency = Usd | Eur | Gbp
-- the "singleton" type
-- If you want to autogenerate this, check out the singletons
-- package on Hackage
data SCurrency (a :: Currency) where
SUsd :: Scurrency Usd
SEur :: Scurrency Eur
SGbp :: Scurrency Gbp
-- the "indexed" type
data CurrencyQty (a :: Currency) where
CurrencyQty :: SCurrency a -> Double -> CurrencyQty a
instance Num (CurrencyQty a) where
... -- you have to manually write this, I guess?
inUsd :: CurrencyQty a -> IO (CurrencyQty Usd)
inUsd (CurrencyQty SUsd x) = return x
inUsd (CurrencyQty SEur x) = fmap (*x) $ currentExchangeRate Usd Eur
inUsd (CurrencyQty SGbp x) = fmap (*x) $ currentExchangeRate Usd Gbp
让我补充一下,您的代码没问题。如果 Haskell 具有完整的依赖类型,则可以在稍作调整后使用您的代码,并避免使用额外的单例类型。但目前Haskell无法避免,还需要付出更多努力。