我们可以抽象类型类吗? [英] Could we abstract over type classes?

查看:104
本文介绍了我们可以抽象类型类吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怀疑是否有更深层次的原因,我们不能抽象类型类(或者我们可以吗?)。

例如,当我们有

  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 Con​​straintKinds,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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆