我们可以抽象类型类吗? [英] Could we abstract over type classes?
问题描述
我怀疑是否有更深层次的原因,我们不能抽象类型类(或者我们可以吗?)。
例如,当我们有
fzip ::(forall a。[a] - > [a]) - > [b] - > [c] - > [(b,c)]
fzip f xs ys = zip(f xs)(f ys)
然后我们可以说
pre $ f $ z']
fzip reverse [1..100] ['a'..'z']
等等。但我们不能
fzip(map succ)[1..100] ['a'..'z']
我们可以解决这个问题:
ezip ::(Enum b,Enum c)=> (全部a.Enum a => [a] - > [a]) - > [b] - > [c] - > [(b,c)]
ezip f xs ys = zip(f xs)(f ys)
同样我们也可以修复
$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ c $ fzip(map(5 *))[1..100] [1.5, 2.3,4.7]
with
nzip ::(Num b,Num c)=> (全部a.Num a => [a] - > [a]) - > [b] - > [c] - > [(b,c)]
nzip f xs ys = zip(f xs)(f ys)
但是,我们不能使用类似的东西来包含 ezip
和 nzip
>
gzip ::(gb,gc)=> (例如,a => [a]→> [a])→> [b] - > [c] - > [(b,c)]
尽管代码是绝对相同的,直到类的名称?
或者我们可以以某种方式?
有趣的是,当实例只是包含函数的记录时,这很容易实现。
你几乎可以用
ConstraintKinds
来做到这一点: { - #LANGUAGE ConstraintKinds,RankNTypes# - }
导入Data.Proxy
gzip: :(gb,gc)=>代理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]
主要区别在于您需要代理
参数,因为GHC无法在没有帮助的情况下推断 g
的正确实例。
I wonder if ithere is a deeper reason that we cannot abstract over type classes (or can we?).
For example, when we have
fzip :: (forall a.[a] -> [a]) -> [b] -> [c] -> [(b,c)]
fzip f xs ys = zip (f xs) (f ys)
then we can say
fzip (drop 42) [1..100] ['a'..'z']
fzip reverse [1..100] ['a'..'z']
and so on. But we cannot
fzip (map succ) [1..100] ['a'..'z']
which we can fix with:
ezip :: (Enum b, Enum c) => (forall a.Enum a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
ezip f xs ys = zip (f xs) (f ys)
and likewise we can fix
fzip (map (5*)) [1..100] [1.5, 2.3, 4.7]
with
nzip :: (Num b, Num c) => (forall a.Num a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
nzip f xs ys = zip (f xs) (f ys)
But is it not embarassing that we cannot subsume ezip
and nzip
with something like:
gzip :: (g b, g c) => (forall a. g a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
though the code is absolutly identical, up to the name of the class? Or can we somehow?
Interestingly, when instances were just records that contained functions, this would be easily possible.
You can almost do this with 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]
The main difference is that you need the Proxy
argument, because GHC is unable to infer the right instantiation for g
without help.
这篇关于我们可以抽象类型类吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!