是否可以拥有"本地"类型类实例?

new*_*cct 18 haskell typeclass

我的意思是定义一个类型类的实例,它应用于函数的本地(letwhere)范围.更重要的是,我希望在这个实例中的函数是闭包,即能够关闭定义实例的词法范围中的变量(这意味着实例在下次调用它的函数时可能会有不同的工作方式).

我可以为您提供一个简化的用例.假设我有一个基于类型类操作的函数.在这个例子中,我使用平方,它可以在任何类型的实例上运行Num(是的,平方非常简单,可以很容易地重新实现,但它代表的是一些可能更复杂的东西).我需要能够按原样使用现有功能(无需更改或重新实现).

square :: Num a => a -> a
square x = x * x
Run Code Online (Sandbox Code Playgroud)

现在,假设我希望在模运算中使用此操作,即加法,乘法等等.这对于任何固定的模数基都很容易实现,但是我希望有一些通用的东西,我可以为不同的模数基重复使用.我希望能够定义这样的东西:

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
Run Code Online (Sandbox Code Playgroud)

关键在于我需要使用from(square)中的函数,该函数要求其参数是一个类型,它是某个类型类的实例.我定义了一个新类型并使其成为一个实例Num; 但是,为了正确执行模运算,它取决于模数基数n,由于此函数的通用设计,模数基数可能会因调用而改变.我希望将实例函数定义为一次性"回调"(如果你愿意),以便square函数定制它此次执行操作的方式(并且只是这次).

一种解决方案可能是将"闭包变量"直接集成到数据类型本身(即ModN (x, n)表示它所属的数字和基数),操作只能从参数中提取此信息.但是,这有几个问题:1)对于多参数函数(例如(*)),它需要在运行时检查这些信息是否匹配,这是丑陋的; 2)实例可能包含0参数"值",我可能希望依赖于闭包变量,但由于它们不包含参数,因此无法从参数中提取它们.

ehi*_*ird 12

提议的扩展具有在我之前的答案中证明的相同问题; 您可以使用本地实例创建Map具有相同键类型但Ord实例不同的两个s ,从而导致所有不变量崩溃.

然而,反射包允许定义这样的ModN类型:你定义一个实例与Reifies约束,并激活该实例特定Ñreify.(我相信隐式参数也可以使这成为可能,但很少使用该扩展.)