Haskell 我们可以抽象类型类吗?
我想知道是否有更深层次的原因,我们不能抽象类型类(或者我们可以?) 例如,当我们Haskell 我们可以抽象类型类吗?,haskell,Haskell,我想知道是否有更深层次的原因,我们不能抽象类型类(或者我们可以?) 例如,当我们 fzip :: (forall a.[a] -> [a]) -> [b] -> [c] -> [(b,c)] fzip f xs ys = zip (f xs) (f ys) 那么我们可以说 fzip (drop 42) [1..100] ['a'..'z'] fzip reverse [1..100] ['a'..'z'] 等等。但我们不能 fzip (map succ) [1..
fzip :: (forall a.[a] -> [a]) -> [b] -> [c] -> [(b,c)]
fzip f xs ys = zip (f xs) (f ys)
那么我们可以说
fzip (drop 42) [1..100] ['a'..'z']
fzip reverse [1..100] ['a'..'z']
等等。但我们不能
fzip (map succ) [1..100] ['a'..'z']
我们可以通过以下方式解决:
ezip :: (Enum b, Enum c) => (forall a.Enum a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
ezip f xs ys = zip (f xs) (f ys)
同样地,我们也可以解决这个问题
fzip (map (5*)) [1..100] [1.5, 2.3, 4.7]
与
但是,我们不能将ezip
和nzip
归为以下内容,这不是很尴尬吗
gzip :: (g b, g c) => (forall a. g a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
虽然代码完全相同,但直到类名为止?
或者我们能不能
有趣的是,当实例只是包含函数的记录时,这是很容易做到的。您几乎可以使用ConstraintKinds
:
{-# LANGUAGE ConstraintKinds, RankNTypes #-}
import Data.Proxy
gzip :: (g b, g c) => Proxy g -> (forall a . g a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
gzip _ f xs ys = zip (f xs) (f ys)
test1 = gzip (Proxy :: Proxy Enum) (map succ) [1 .. 100] ['a' .. 'z']
test2 = gzip (Proxy :: Proxy Num) (map (5*)) [1 .. 100] [1.5, 2.3, 4.7]
主要区别在于您需要Proxy
参数,因为GHC无法在没有帮助的情况下推断g
的正确实例化。为约束添加一个参数:
{-# LANGUAGE PartialTypeSignatures #-}
import Data.Proxy
gzip :: (g b, g c) => Proxy g -> (forall a. g a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
gzip _ f bs cs = zip (f bs) (f cs)
> gzip (Proxy :: _ Enum) [0, 1] "ab"
[(1,'b'),(2,'c')]
GHC认为仅出现在约束中的约束参数是不明确的,因此我们需要在代理中显式记录它们。GHC的
约束
系统期望可解性是*单态可判定的(所有带有种类约束的类型都由一个或多个已知类型预测-也就是说,typeclass高层结构在其typeclass标头中不能是可变的),我认为这可能是PartialTypeSignatures
@kosmikus的一个有趣用法。我厌倦了双重代理:pye。我一定会记住这一点。尽管我仍然不太喜欢PartialTypeSignatures
在某种程度上将类型级漏洞与类型级代码推理混为一谈。我希望它们在语法上有所不同nt与Agda类似。我希望GHC 8.0中的显式类型应用程序能够让我们彻底摆脱Proxy
和KProxy
(我想知道当前的“不明确类型”错误会发生什么)。是的,希望会有很多新的可能性:)
{-# LANGUAGE PartialTypeSignatures #-}
import Data.Proxy
gzip :: (g b, g c) => Proxy g -> (forall a. g a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
gzip _ f bs cs = zip (f bs) (f cs)
> gzip (Proxy :: _ Enum) [0, 1] "ab"
[(1,'b'),(2,'c')]