如何组合哈斯克尔图表包中的"环形楔形"和"楔形"?



图包的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

事实上,annularWedgewedge有不同的约束,这让我很惊讶:

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 #-}添加到文件的顶部。需要明确的是,添加这些扩展都是安全的(有些扩展,如重叠实例或不可判定的实例应该让您在启用它们之前暂停,但这些扩展大多是安全的)

虽然不明显,但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约束,因为该实例是在Linear.Vector中定义Additive的,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中定义,相应的V2实例使用arctan函数(这是在追逐更多依赖项后获得的)。

请遵循GHC给您的建议:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
import Diagrams
import Diagrams.TwoD.Arc
mywedge r2 r1 d a
  | r1 == 0   = wedge r2 d a
  | otherwise = annularWedge r2 r1 d a

一般来说,我更喜欢在处理时使用<=比较使用浮点数,例如:

  | r1 <= 1e-10 = wedge r2 d 1

最新更新