Functor 实例是否可以声明为函数的附加类型限制
Can Functor instance be declared with additional type restriction for function
我正在努力将 GHC/Arr.hs 移植到 Frege。
数组定义:
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
有限制的仿函数吗?
不,这不可能。
如果您 Array
基于 JArray
并且想要一个仿函数实例,则不得使用任何出现 ArrayElem(或任何其他附加)上下文的函数。
另一种说法是,您不能将 Array
基于类型安全的 java 数组,而必须处理 java 类型 Object[]
的数组。因为,正如您毫无疑问指出的那样,ArrayElem
类型 class 只是一个技巧,可以在创建 java 数组时提供正确的 java 类型。当然,这对于与 Java 交互和出于性能原因很重要。
请注意,类型安全 java 数组还有另一个问题。假设我们想要创建一个 Double
的数组(但相同的参数适用于任何其他元素类型)。 AFAIK,Haskell 要求 Arrays 元素必须是惰性的。因此我们真的不能使用 java 类型 double[]
(JArray Double
将是 Frege 的对应物)来建模它。因为,如果我们这样做,每个数组元素都必须在设置后立即求值。
出于这个原因,我建议您使用一些通用的自定义数组元素类型,例如
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))}
现在,你的仿函数实例可以写了,因为 ArrayElem 约束没有出现,因为当你访问 elems
数组时,编译器知道你有 AElem
个元素并且可以并且将会提供正确的实例。
此外,AElem
的构造和 AElem
的使用作为实际数组元素不会 对实际值施加严格。
不用说,Array 模块的用户不应该(不需要)知道那些实现细节,即 AElem
类型。
我正在努力将 GHC/Arr.hs 移植到 Frege。
数组定义:
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
有限制的仿函数吗?
不,这不可能。
如果您 Array
基于 JArray
并且想要一个仿函数实例,则不得使用任何出现 ArrayElem(或任何其他附加)上下文的函数。
另一种说法是,您不能将 Array
基于类型安全的 java 数组,而必须处理 java 类型 Object[]
的数组。因为,正如您毫无疑问指出的那样,ArrayElem
类型 class 只是一个技巧,可以在创建 java 数组时提供正确的 java 类型。当然,这对于与 Java 交互和出于性能原因很重要。
请注意,类型安全 java 数组还有另一个问题。假设我们想要创建一个 Double
的数组(但相同的参数适用于任何其他元素类型)。 AFAIK,Haskell 要求 Arrays 元素必须是惰性的。因此我们真的不能使用 java 类型 double[]
(JArray Double
将是 Frege 的对应物)来建模它。因为,如果我们这样做,每个数组元素都必须在设置后立即求值。
出于这个原因,我建议您使用一些通用的自定义数组元素类型,例如
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))}
现在,你的仿函数实例可以写了,因为 ArrayElem 约束没有出现,因为当你访问 elems
数组时,编译器知道你有 AElem
个元素并且可以并且将会提供正确的实例。
此外,AElem
的构造和 AElem
的使用作为实际数组元素不会 对实际值施加严格。
不用说,Array 模块的用户不应该(不需要)知道那些实现细节,即 AElem
类型。