类型约束中的逻辑蕴涵(Haskell)
我如何表达容器满足某些“透明度属性”的想法?例如,考虑容器类型<代码> v<代码>,这样<代码>显示暗示“代码>显示(V A)< /代码>。 用例是,我希望有一个函数,在这个函数中,被调用方决定使用哪个容器,但保证容器在许多类型类约束方面表现良好 下面是一个(非工作)示例,说明我的想法:类型约束中的逻辑蕴涵(Haskell),haskell,typeclass,Haskell,Typeclass,我如何表达容器满足某些“透明度属性”的想法?例如,考虑容器类型 v,这样显示暗示“代码>显示(V A)< /代码>。 用例是,我希望有一个函数,在这个函数中,被调用方决定使用哪个容器,但保证容器在许多类型类约束方面表现良好 下面是一个(非工作)示例,说明我的想法: mapUnknown :: (forall v. (Functor v, (forall n. Num n => Num (v n)) => v b -> a)) -> [b] -
mapUnknown :: (forall v. (Functor v, (forall n. Num n => Num (v n)) => v b -> a))
-> [b] -> [a]
其思想是传入一个函数,该函数必须能够处理任何容器类型v
。可以保证v
是一个Functor
,并且Num b
意味着Num(vb)
。如果传入的b
不是Num
,则忽略该规则
这可能吗
注:
以下操作不起作用:
class Container c a where
foo :: c a -> [a]
instance forall a c. (Container c a, Show a) => Show (c a) where
show _ = "whatever"
f :: (Container c a, Show a) => c a -> String
f as =
show as
这是因为我们可以定义一个实例
容器va
,也可以显示(va)
。然后,GHC无法确定是使用Container
定义的show
还是使用show(va)
定义的show。我们不想定义一个新的show
函数,我们只想在知道容器的类型后断言它存在。好吧,如果我理解正确,您想创建一个类,比如说NumToNum
,这样,编译器就可以从两个实例Num v
和Num n
中推断出Num(v n)
存在一个实例。以下是您如何完成此任务的方法
这里的关键是创建一个类型,比如说,NumI::*->*
,这样就不会有任何类型的值numin
,除非n
属于Num
类。严格地说,这是不可能的,因为Haskell的任何类型都有人居住(至少有(| |
)。但是,如果您避免显式地将实现方法标记为未定义的
,并深入研究深层递归,那么这样做会相对安全:
data NumI n where NumI :: Num n => NumI n
因此,如果n
不属于Num
类,则仍然存在Num n
类型的undefined
,但没有太多其他值
当然,您需要GADTs
扩展
现在,可以这样定义上述类:
class NumToNum v where numToNum :: Num n => NumI (v n)
有了它,您可以通过模式匹配获得Num(vn)
实例:
case (numToNum :: NumI (v n)) of NumI => do_something
这里的do\u something
已经知道Num(vn)
实例,这要感谢构造函数NumI
的类型签名
声明NumToNum
类的实例很容易,您只需说
data V n = -- whatever
instance Num n => Num (V n) where -- some implementation
instance NumToNum V where numToNum = NumI
能否创建一个名为Container的类型类,然后将所有容器数据类型注册为该类型类的实例?然后,您可以代替
mapnknown
执行mapContainer
,该函数将是Container
类型类所需的函数。请参见编辑--它不起作用。您尝试执行的操作将不起作用,因为forall n。Num n=>Num(v n)
不是有效的约束。但是,使用,可以将所需的约束具体化为类型为forall n的函数。Num n:-Num(v n)
。您的函数的完整类型可以是(对于所有n.Num n:-Num(vn))->(vb->a)->[b]->[a]
——但我不知道您实际希望它做什么。如果启用了OverlappingInstances
,则第二个示例可以工作。抱歉,我还没有完全理解。如果我有一个函数签名(Applicative v,NumToNum v)=>v String->()
编译器会自动意识到我创建的任何v Double
都是Num
s吗?或者我必须将所有内容包装在模式匹配中以强制实现它吗?来自数据的:-
约束在这里有用吗?是的,您必须在任何地方使用模式匹配。是的,:-
似乎是一条路要走;我只是教你怎么自己做。