在 Arrow 库中实现"第一"



我不明白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 | (***)) #-}

它告诉编译器,即使提供了默认值,除非实例指定arrfirst(***)之一,否则实例是不完整的。 因此,对需求进行了编码和检查。


至于你的评论:

不一定我可以保留默认值,然后递归将根据定义发生。 具体实现不是这里的问题...

不能在没有实例的情况下使用类型类的方法。 甚至很少可以尝试,因为方法的类型总是引用类型,例如

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.

如果程序不编译,则没有无限递归!

最新更新