当前位置:  开发笔记 > 编程语言 > 正文

我们可以抽象出类型类吗?

如何解决《我们可以抽象出类型类吗?》经验,为你挑选了2个好方法。

我想知道是否有更深层次的原因我们不能抽象出类型类(或者我们可以吗?).

例如,当我们有

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]

nzip :: (Num b, Num c) => (forall a.Num a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]
nzip f xs ys = zip (f xs) (f ys)

然而,不尴尬,我们不能归入ezipnzip喜欢的东西:

gzip :: (g b, g c) => (forall a. g a => [a] -> [a]) -> [b] -> [c] -> [(b,c)]

虽然代码是绝对相同的,但直到类的名称?或者我们能以某种方式?

有趣的是,当实例只是包含函数的记录时,这很容易实现.



1> kosmikus..:

几乎可以这样做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没有帮助的情况下推断出正确的实例化.



2> András Kovác..:

Proxy为约束添加参数:

{-# 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认为约束参数仅出现在不明确的约束中,因此我们需要在代理中明确记录它们.

推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有