haskell - Arrow 库中 `first` 的实现

标签 haskell arrows mutual-recursion default-implementation infinite-recursion

我不明白库中 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)

第一个 f(f *** id) 也就是 (第一个 f >>> arr swap >>> 第一个 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’

这是因为source配有 MINIMAL pragma :

{-# MINIMAL arr, (first | (***)) #-}

它告诉编译器,即使提供了默认值,实例也不完整,除非它指定 arrfirst(*** )。因此,需求被编码和检查。


至于您的评论:

Not necesseraly I can leave the default and then the recursion will take place by definition. specific implementation are not the question here...

如果没有实例,则无法使用类型类的方法。几乎不可能尝试,因为方法的类型总是引用类型,例如

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.

如果程序无法编译,则不会无限递归!)

关于haskell - Arrow 库中 `first` 的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57744404/

相关文章:

haskell - Opaleye 中链接表的数组聚合

haskell - 休斯的斐波那契流

haskell - Haskell相互递归的澄清

javascript - 合并排序的这种实现是否使用相互递归?

haskell - 如何加速(或内存)一系列相互递归的函数

haskell - 如何使用 Monad 的 (->) 实例以及 (->) 的困惑

list - 以所有可能性在 Haskell 中旋转列表

haskell - 这种请求-响应类型是否有标准抽象?

programming-languages - 非升降式产品的缺点?

list - 用 Foldl 剪掉任何内容