我的意思是定义一个在函数的局部(let或where)作用域中应用的类型类的实例。更重要的是,我希望这个实例中的函数是闭包的,即能够关闭定义实例的词法作用域中的变量(这意味着下次调用该实例所在的函数时,该实例可能会以不同的方式工作)。
我可以为您提供一个简化的用例。假设我有一个函数,它基于一个类型类对一个类型进行操作。在这个例子中,我使用了平方,它可以在任何实例Num的类型上操作(是的,平方非常简单,可以很容易地重新实现,但它代替了一些可能更复杂的东西)。我需要能够按原样使用现有函数(无需更改或重新实现它)。
square :: Num a => a -> a
square x = x * x现在,假设我希望在模算术中使用这个操作,即加法、乘法等对某个数字取模。这对于任何固定的模基都很容易实现,但我想要有一些通用的东西,我可以在不同的模基上重用。我希望能够定义这样的东西:
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参数“值”,但由于它们不包含参数,因此无法从参数中提取它们。
发布于 2012-03-03 20:34:19
建议的扩展具有我的this previous answer中演示的相同问题;您可以使用本地实例创建具有相同键类型但不同Ord实例的两个Map,从而导致所有不变量崩溃。
但是,reflection包允许您定义这样的ModN类型:使用Reifies约束定义单个实例,并使用reify激活特定n的实例。(我相信implicit parameters也会让这成为可能,但这个扩展很少使用。)
https://stackoverflow.com/questions/9545866
复制相似问题