你是对的,如果你实现这样的箭头:
instance Arrow MyType where
arr f = ...
然后尝试使用first
or (***)
,你会得到一个无限循环,因为实现相互引用是非生产性的。但是,以这种方式定义默认方法允许您实例Arrow
化为
instance Arrow MyType where
arr f = ...
first t = ...
或者
instance Arrow MyType where
arr f = ...
t *** t' = ...
哪个更方便/更有效(取决于您关心的内容),并且缺少的方法将根据您指定的方法自动定义。
如果我们尝试实例化Arrow
而不给出first
or的实现(***)
,我们将收到以下警告:
warning: [-Wmissing-methods]
• No explicit implementation for
either ‘first’ or ‘***’
• In the instance declaration for ‘Arrow MyType’
这是因为源带有一个MINIMAL
pragma:
{-# MINIMAL arr, (first | (***)) #-}
它告诉编译器,即使提供了默认值,实例也不完整,除非它指定arr
了first
or之一(***)
。所以需求被编码和检查。
至于你的评论:
不一定我可以保留默认值,然后递归将根据定义进行。具体实现不是这里的问题......
没有实例就不能使用类型类的方法。甚至很少可以尝试,因为方法的类型总是引用类型,例如
class Arrow k where
first :: k a b -> k (a,c) (b,c)
...
当您使用 时first
,您必须有一个特定k
的想法才能使用结果,例如
print $ first (arr id) (1,2) -- using it at k ~ (->)
print =<< runKleisli (first (arr id)) (1,2) -- using it at Kleisli IO
在某些时候,程序的类型约束将k
确定为具体的东西,这就是使用的实例。你不能使用没有实例的类。
(即使在事情以无法确定特定实例的方式排列的情况下,经典的例子是
show . read :: String -> String
编译器只会对你大喊大叫
• Ambiguous type variable ‘a0’ arising from a use of ‘read’
prevents the constraint ‘(Read a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
如果程序无法编译,则没有无限递归!)