我不明白first
在库中的实现。
first
似乎用***
递归定义 - 我不知道递归何时结束!?
first :: a b c -> a (b,d) (c,d)
first = (*** id)
和
(***) :: a b c -> a b' c' -> a (b,b') (c,c')
f *** g = first f >>> arr swap >>> first g >>> arr swap
where swap ~(x,y) = (y,x)
first f
(f *** id)
哪个是(first f >>> arr swap >>> first id...)
,新的first
将是另一个(*** id)
等等......
你是对的,如果你实现这样的箭头:
instance Arrow MyType where
arr f = ...
然后尝试使用first
或(***)
,你会得到一个无限循环,因为实现相互引用是非生产性的。 但是,以这种方式定义默认方法允许您将Arrow
实例化为
instance Arrow MyType where
arr f = ...
first t = ...
或
instance Arrow MyType where
arr f = ...
t *** t' = ...
以更方便/高效(取决于您关心的内容(为准,并且缺少的方法将根据您指定的方法自动定义。
如果我们尝试实例化Arrow
而不给出first
或(***)
的实现,我们将收到以下警告:
warning: [-Wmissing-methods]
• No explicit implementation for
either ‘first’ or ‘***’
• In the instance declaration for ‘Arrow MyType’
这是因为源代码带有MINIMAL
编译指示:
{-# MINIMAL arr, (first | (***)) #-}
它告诉编译器,即使提供了默认值,除非实例指定arr
和first
或(***)
之一,否则实例是不完整的。 因此,对需求进行了编码和检查。
至于你的评论:
不一定我可以保留默认值,然后递归将根据定义发生。 具体实现不是这里的问题...
不能在没有实例的情况下使用类型类的方法。 甚至很少可以尝试,因为方法的类型总是引用类型,例如
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.
如果程序不编译,则没有无限递归!