事实证明,图表包的annularWedge
函数的内半径不能为0。您必须改为使用wedge
。
对我来说,内半径0只是annularWedge
的简并情况,其行为应类似于wedge
,因此我尝试将它们结合起来:
mywedge r2 r1 d a
| r1 == 0 = wedge r2 d a
| otherwise = annularWedge r2 r1 d a
当然,它不起作用,而且我无法弄清楚该错误是什么意思:
Non type-variable argument in the constraint: RealFloat (N t)
(Use FlexibleContexts to permit this)
When checking that ‘mywedge’ has the inferred type
mywedge :: forall t.
(RealFloat (N t), TrailLike t, V t ~ V2) =>
N t -> N t -> Direction V2 (N t) -> Angle (N t) -> t
实际上,事实证明
annularWedge
和wedge
具有不同的约束,这使我感到惊讶:annularWedge :: (TrailLike t, V t ~ V2, N t ~ n, RealFloat n) => n -> n -> Direction V2 n -> Angle n -> t
wedge :: (InSpace V2 n t, OrderedField n, TrailLike t) => n -> Direction V2 n -> Angle n -> t
那么,如何将这两个函数组合成一个合理的函数,该函数接受内部半径为0并做正确的事情?
最佳答案
解决方案很简单。正如ErikR所说,在文件顶部添加{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
。明确地说,这些都是要添加的安全扩展名(某些扩展名,例如重叠的实例或不确定的实例,应使您在启用它们之前先暂停一下,但这些扩展名mostly是安全的)
尽管并不明显,但wedge
签名的约束严格弱于annularWedge
的约束。
如果您对签名为何如此不同感到好奇,请继续阅读...
对于初学者来说,一旦找到约束,它们并没有什么不同。让我们从wedge
开始。
(InSpace V2 n t, OrderedField n, TrailLike t)
查看
InSpace
的定义,您会发现它没有任何功能,实际上就像一个同义词:(V a ~ v, N a ~ n, Additive v, Num n) => InSpace v n a
。然后,我们可以将InSpace V2 n t
扩展为(V t ~ V2, N t ~ n, Additive V2, Num n)
。同样,OrderedField
只是(Floating n, Ord n)
的简写。现在,wedge
的约束看起来像(TrailLike t, V t ~ V2, N t ~ n, Additive V2, Num n, Floating n, Ord n)
但是,事实证明,我们甚至可以删除
Additive V2
约束,因为在Additive
的情况下该实例已定义为where Linear.Vector
is defined in Num n
并且Num n => Fractional n => Floating n
是冗余的。这使我们对wedge
的约束更加简单(TrailLike t, V t ~ V2, N t ~ n, Floating n, Ord n)
看起来很像
annularWedge
的约束。实际上,唯一的区别是与wedge
约束(Floating n, Ord n)
相比,annularWedge
约束RealFloat n
。在这一点上,约束非常相似,因此值得研究wedge
的代码。事实证明,wedge
使用了在_theta
中定义的HasTheta
,并且corresponding V2
instance使用了反正切函数(在追逐了更多的依赖项之后才得到)。