是否有可能有一个“本地”类型实例?
我的意思是定义一个适用于函数中的本地(let
或where
)作用域的类型实例。更重要的是,我希望在这个实例中的函数是闭包,即能够关闭定义实例的词法范围中的变量(这意味着实例可能在下次调用它的函数时以不同方式工作) )。是否有可能有一个“本地”类型实例?
我可以给你一个简单的用例。假设我有一个基于类型类的类型的函数。在这个例子中,我使用了平方,它可以对任何类型的实例进行操作,例如Num
(是的,平方很简单,可以很容易地重新实现,但它可能会更复杂)。我需要能够按原样使用现有功能(无需更改或重新实现)。
square :: Num a => a -> a
square x = x * x
现在,假设我希望在模运算中使用这个操作,即加法,乘法等mod某些数字。这对于任何固定的模基很容易实现,但我想要有一些通用的东西,我可以重新使用不同的基模。我希望能够来定义是这样的:
newtype ModN = ModN Integer deriving (Eq, Show)
-- computes (x * x) mod n
squareModN ::
squareModN x n =
let instance Num ModN where
ModN x * ModN y = ModN ((x * y) `mod` n) -- modular multiplication
_ + _ = undefined -- the rest are unimplemented for simplicity
negate _ = undefined
abs _ = undefined
signum _ = undefined
fromInteger _ = undefined
in let ModN y = square (ModN x)
in y
这样做的一点是,我需要使用的功能,从上面(square
),要求它的参数是一个类型,它是有一定的实例类型的类。我定义了一个新类型并将其作为Num
的一个实例;然而,为了正确地执行模运算,它取决于基模n
,由于该函数的通用设计,其可能因呼叫而改变。我希望将实例函数定义为square
函数的一次性“回调”(如果您愿意的话),以定制它此次(以及仅此一次)执行操作的方式。
一种解决方案可能是将“闭包变量”直接集成到数据类型本身中(即ModN (x, n)
来表示它所属的数量和基数),操作可以从参数中提取这些信息。然而,这有几个问题:1)对于多参数函数(例如(*)
),它需要在运行时检查这些信息是否匹配,这很丑陋; 2)实例可能包含0参数的“值”,我可能想依赖于闭包变量,但是,由于它们不包含参数,因此无法从参数中提取它们。
建议的扩展有我的this previous answer中显示的相同问题;您可以使用本地实例创建两个具有相同密钥类型但不同Ord
实例的Map
,从而导致所有不变量崩溃。
然而,reflection包允许定义这样的ModN
类型:你定义一个实例与Reifies
约束,并激活该实例特定Ñ与reify
。 (我相信implicit parameters也会使这成为可能,但这种扩展很少使用。)
不,你不能有本地实例。对于模块化算法,Oleg Kiselyov和CC Shan已经在他们的论文“隐式配置”中解决了这个问题 - http://www.cs.rutgers.edu/~ccshan/prepose/prepose.pdf。我个人倾向于避免这种情况,并简单地为模块化的基础 - 即Z7,Z12做一个新的类型。 Conal Elliott提供了另一种选择替代类型的模式,请参阅CxMonoid的文章“适用性数据驱动计算” - http://conal.net/papers/data-driven/paper.pdf – 2012-03-03 12:42:52
事实上,反射包本质上是Oleg纸的包装版本。 – ehird 2012-03-03 12:56:49
关于Haskell的现状:没有。实例将随处随地都可以到达。关于未来对Haskell的可能调整:也许。关于使用你自己的机制,而不是typeclasses:是的。 – 2012-03-03 22:01:02