haskell - 在 Haskell 中,如何将约束附加到参数新类型,以便它们自动应用于使用它的任何类实例?
问题描述
假设我有一个这样定义的参数类型:
newtype FancyComplex a b = FancyComplex (a, b)
我打算永远不要将此新类型用于除数字参数之外的任何其他参数。我的意思是,对于我可能做的任何实现,我都知道参数a
并且b
将始终是Num
.
我在这个问题中读到你可以这样做: Can a typeclass constraint be used in a newtype definition?
{-# LANGUAGE RankNTypes #-}
newtype (Num a, Num b) => FancyComplex a b = FancyComplex (a, b)
然而,这还不够。如果我写任何这样的课程:
class StupidClass x where add :: x -> x -> x
那我应该可以写了
instance StupidClass (FancyComplex a b) where
add (FancyComplex (a, b)) (FancyComplex (a', b')) = FancyComplex (a+a', b+b')
但是没有 GHC 会告诉我说我没有执行该Num
要求。所以我每次都被迫这样做:
instance (Num a, Num b) => StupidClass (FancyComplex a b) where
add (FancyComplex (a, b)) (FancyComplex (a', b')) = FancyComplex (a+a', b+b')
在 newtype 定义中编写约束所做的所有事情都是迫使我每次都明确地编写约束。好的,如果我忘记了,这仍然很有用。但我当然希望不必每次都重写约束。
如何自动和隐式地从 newtype 定义中继承约束?这可能吗?如果没有,有理由不这样做吗?
目前我的弱解决方法是定义一个类型别名type FancyComplexReqs a b = (Num a, Num b)
谢谢
解决方案
在 GADT 中编码约束,如下所示:
{-# LANGUAGE GADTs #-}
data FancyComplex a b where
FancyComplex :: (Num a, Num b) => a -> b -> FancyComplex a b
class StupidClass x where add :: x -> x -> x
instance StupidClass (FancyComplex a b) where
add (FancyComplex a b) (FancyComplex a' b') = FancyComplex (a+a') (b+b')
你必须切换到data
fromnewtype
因为约束变成了字典,它确实具有运行时表示。但是,通过这样做,我们可以摆脱您的元组,从而节省data
成本。
推荐阅读
- ruby-on-rails - Rails 中的 PUB/SUB 使用 ActionCable 和 Sidekiq
- ios - CoreData Fetch Request crash initWithCoder:]: unrecognized selector sent to instance
- android - NoSuchMethodError: 没有静态方法 ()Ljava/lang/Thread
- google-cloud-dlp - Google DLP 是否可以在不处理澳大利亚以外其他地区的数据的情况下使用
- go - 将 interface{} 从 JSON 转换为多种具体类型之一
- db2 - 动态 SQL DB2 中的 In Out 参数
- hangfire - Hangfire 限制作业计数取决于服务器 cpu / 内存状态
- typescript - [] 是 Typescript 中的有效类型吗?
- r - 两种不同的设置,并在 Shiny 中并排显示结果
- apache-kafka-streams - kafka流聚合 - 数据丢失