我想为可减类型创建一个类型类,这样
- 值类型实现
Ord
。 - 有一个
减
函数。 - 它支持
UTCTime
、Double
和Int
(或可选的任何Num
类型) 有一个
Delta
类型,它可能与源值类型不同。例如,对于UTCTime
值类型,增量类型为NominalDiffTime
。对于Int
、Double
,增量类型将与值类型相同。diffUTCTime::UTCTime -> UTCTime -> NominalDiffTime
增量类型应实现
Num
。
这根本不起作用,但希望能传达我想要做的事情
class Ord a => Subtractable a where
-- The type alias for the delta type
type Num b => b
-- The subtract function
subtractValues :: a -> a -> b
最佳答案
您可以使用type families来做到这一点:
class Subtractable a where
type Diff a :: *
subtractValues :: a -> a -> Diff a
在您的示例中 UTCTime
这将是:
{-# LANGUAGE TypeFamilies #-}
module Stackoverflow where
import Data.Time.Clock
class Subtractable a where
type Diff a :: *
subtractValues :: a -> a -> Diff a
instance Subtractable UTCTime where
type Diff UTCTime = NominalDiffTime
subtractValues = diffUTCTime
并产生这样的结果:
λ> t1 <- getCurrentTime
λ> t2 <- getCurrentTime
λ> subtractValues t2 t1
5.327944s
(如你所见,我打字速度很慢;))
您可以在Num
上添加约束如果添加 {-# LANGUAGE FlexibleContexts #-}
并更改 class
至:
class (Num (Diff a)) => Subtractable a where
type Diff a :: *
subtractValues :: a -> a -> Diff a
<小时/>
Int
的实例
instance Subtractable Int where
type Diff Int = Int
subtractValues = (-)
<小时/>
使用MultiParamTypeClasses
和FunctionalDependencies
您还可以使用 multiparam-type-classes 和 functional dependencies 来做到这一点但我更喜欢类型家庭方法 - 但这显然是我的观点
无论如何,这是一个使用 FD 的版本:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
module StackOverflow where
import Data.Time.Clock
class Num b => Subtractable a b | a -> b where
subtractValues :: a -> a -> b
instance Subtractable UTCTime NominalDiffTime where
subtractValues = diffUTCTime
<小时/>
备注
- 刚刚看到我应该输入
Delta
而不是Diff
- 我想你明白了 - 如果您尝试对一般
Num a
执行此操作你会遇到非常讨厌的东西(编译器将无法决定基本上选择哪个Diff a
) - 所以现在我看不出有什么办法可以让这个 ATM 工作,但周围可能有人可以想出一个 < em>诡计(或者告诉我哪里我完全没有捕获要点;))
关于haskell - 如何实现一个简单的 Subtractable 类型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35023606/