我正在努力将GHC / Arr.hs移植到弗雷格。
定义了数组:
data Array i e = Array{u,l::i,n::Int,elems::(JArray e)}
有功能:
amap :: (Ix i, ArrayElem e) => (a -> b) -> Array i a -> Array i b
现在,我不知道如何为它定义Functor
实例,因为
instance (Ix i) => Functor (Array i) where
fmap = amap
但是编译器抱怨推断类型比预期更受约束,看似真实。我可以将Array
作为功能ArrayElem -> ArrayElem
的重新绑定的仿函数吗?
答案 0 :(得分:3)
不,这是不可能的。
如果您将Array
基于JArray
并想要一个仿函数实例,则不得使用ArrayElem(或任何其他附加)上下文中出现的任何函数。
另一种说法是你不能将Array
基于类型安全的java数组,但必须处理类型为Object[]
的java数组。因为,正如您所指出的那样,ArrayElem
类型类只是能够在创建Java数组时提供正确的java类型的技巧。当然,这对于与Java的接口和性能原因很重要。
请注意,类型安全java数组存在另一个问题。假设我们想要创建一个Double
数组(但是同一个参数适用于任何其他元素类型)。 AFAIK,Haskell要求Arrays元素必须是懒惰的。因此,我们实际上不能使用java类型double[]
(JArray Double
将成为弗雷格对应物)来对其进行建模。因为,如果我们这样做,每个数组元素一旦设置就必须进行评估。
出于这个原因,我建议你使用一些通用的自定义数组元素类型,比如
data AElem a = AE () a
mkAE = A ()
unAE (AE _ x) = x
derive ArrayElement AElem
并更改您的定义:
data Array i e = Array{u,l::i,n::Int,elems::(JArray (AElem e))}
现在,您的functor实例可以编写,因为不会出现ArrayElem约束,因为当您访问elems
数组时,编译器知道您有AElem
个元素,并且可以并且将提供正确的例子。
此外,AElem
的构造和AElem
s作为实际数组元素的使用不对实际值施加严格性。
毋庸置疑,Array模块的用户不应(需要)了解这些实现细节,即AElem
类型。