可以使用与Haskell中使用GADT定义的数据类型的模式匹配
我正在尝试定义复杂
datatype,我希望构造函数能够以任何数字为例,因此我想使用通用类型,只要它确实实现了num
实例
我是我们的gadt
s,因为我理解datatypecontexts
语言扩展是“ misfeature “即使我认为在这种情况下这是有用的...
无论如何,这是我的代码:
data Complex where
Real :: ( Num num, Show num ) => num -> Complex
Imaginary :: ( Num num, Show num ) => num -> Complex
Complex :: ( Num num, Show num ) => num -> num -> Complex
real :: ( Num num, Show num ) => Complex -> num
real (Real r) = r
real (Imaginary _i ) = 0
real (Complex r _i ) = r
这里real
实现给出以下错误:
Couldn't match expected type ‘num’ with actual type ‘num1’
‘num1’ is a rigid type variable bound by
a pattern with constructor:
Real :: forall num. (Num num, Show num) => num -> Complex,
in an equation for ‘real’
at <...>/Complex.hs:29:7-12
‘num’ is a rigid type variable bound by
the type signature for:
real :: forall num. (Num num, Show num) => Complex -> num
at <...>/Complex.hs:28:1-47
• In the expression: r
In an equation for ‘real’: real (Real r) = r
• Relevant bindings include
r :: num1
(bound at <...>/Complex.hs:29:12)
real :: Complex -> num
(bound at <...>/Complex.hs:29:1)
据我所知,这是由于返回所致类型可以解释为不同... 因此,我尝试删除类型的定义,并让GHC
对他的魔术进行类型的魔术,但事实证明类型签名是相同的...
有人可以向我解释一下这里有什么问题吗?
I'm trying to define a Complex
datatype, and I want the constructors to be able to take any number as instance, so I would like to use a generic type as long as it does implement a Num
instance
I'm usind GADT
s in order to do so since to my understanding the DataTypeContexts
language extension was a "misfeature" even if I think that would have been useful in this case...
In any case this is my code:
data Complex where
Real :: ( Num num, Show num ) => num -> Complex
Imaginary :: ( Num num, Show num ) => num -> Complex
Complex :: ( Num num, Show num ) => num -> num -> Complex
real :: ( Num num, Show num ) => Complex -> num
real (Real r) = r
real (Imaginary _i ) = 0
real (Complex r _i ) = r
here the real
implementation gives the following error:
Couldn't match expected type ‘num’ with actual type ‘num1’
‘num1’ is a rigid type variable bound by
a pattern with constructor:
Real :: forall num. (Num num, Show num) => num -> Complex,
in an equation for ‘real’
at <...>/Complex.hs:29:7-12
‘num’ is a rigid type variable bound by
the type signature for:
real :: forall num. (Num num, Show num) => Complex -> num
at <...>/Complex.hs:28:1-47
• In the expression: r
In an equation for ‘real’: real (Real r) = r
• Relevant bindings include
r :: num1
(bound at <...>/Complex.hs:29:12)
real :: Complex -> num
(bound at <...>/Complex.hs:29:1)
which to my understanding is due to the return type do be interpreted as different...
so I tried removing the type definition and letting ghc
do his magic with the type but turns out the type signature was the same...
can anyone please explain to me what is wrong here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是,这些定义允许您选择不同类型时((1)构建
复杂
值以及(2)应用real
函数时。这两种情况并非以任何方式相互连接,因此没有任何迫使它们之间的类型相同。例如:d
的定义要求real
函数返回double
,但没有double
包装在c
的内部,只有int
。至于解决方案有两个可能的方法:(1)在这两个点之间建立连接,强迫类型相同,(2)允许内部类型转换为任何其他数字类型。
要在两个点之间建立类型级的连接,我们需要使用两个点上存在的类型。那是什么类型?显然,这就是
c
的类型。因此,我们需要使c
的类型以某种方式传达其中包裹的内容:请注意,我实际上并不需要Gadts。
要允许类型转换,您需要需要
num
类型的其他类型类。类num
可以从任何积分类型中转换,但是没有办法将转换为 任何这样的类型t很有意义:3.1415不能有意义地转换为积分类型。因此,您必须提出自己的转换方式,并为所有允许类型实施它:
要清楚,我认为第二个选项非常疯狂。我只提供了插图。不要做。使用选项1。
Problem is, these definitions allow you to choose different types when (1) constructing a
Complex
value and when (2) applying thereal
function. These two situations are not connected to each other in any way, so there is nothing to force the type to be the same between them. For example:The definition of
d
requires thereal
function to return aDouble
, but there is noDouble
wrapped inside ofc
, there is onlyInt
.As for solutions, there are two possible ones: (1) establish a connection between these two points, forcing the type to be the same, and (2) allow the type inside to be converted to any other numeric type.
To establish a type-level connection between two points, we need to use a type that is present at both points. What type would that be? Quite obviously, that's the type of
c
. So we need to make the type ofc
somehow convey what's wrapped inside it:Note that I don't actually need GADTs for this.
To allow type conversion, you'll need to require another type class for the
num
type. The classNum
has a way to convert from any integral type, but there is no way to convert to any such type, because it doesn't make sense: 3.1415 can't be meaningfully converted to an integral type.So you'll have to come up with your own way to convert, and implement it for all allowed types too:
Just to be clear, I consider the second option quite insane. I only provided it for illustration. Don't do it. Go with option 1.