I don't understand the implementation of first
in the library.
first
seems to be defined recursively with ***
-- I don't see when the recursion shall end!?
first :: a b c -> a (b,d) (c,d)
first = (*** id)
and
(***) :: 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
is (f *** id)
which is (first f >>> arr swap >>> first id...)
and the new first
will be another (*** id)
and so on...
You are correct, if you implement an arrow like this:
and then try to use
first
or(***)
, you will get an infinite loop since the implementations refer to each other non-productively. However, defining the default methods this way allows you to instantiateArrow
as eitheror
whichever is more convenient/efficient (depending on what you care about), and the missing method will be defined automatically in terms of the one you did specify.
If we try to instantiate
Arrow
without giving an implementation offirst
or(***)
, we will get the following warning:This is because the source comes with a
MINIMAL
pragma:which tells the compiler that, even though defaults are supplied, an instance is not complete unless it specifies
arr
and one offirst
or(***)
. So the requirement is encoded and checked.As for your comment:
You can't use methods of a typeclass without an instance. It's seldom even possible to try, because the types of methods always refer to the type, e.g.
When you use
first
, you have to have a specifick
in mind in order to use the result, e.g.At some point the type constraints of the program will pin
k
down to be something concrete, and that is the instance that is used. You can't use a class without an instance.(And even in the cases where things line up in such a way that a specific instance is not determined, the classic example being
The compiler will just yell at you
No infinite recursion if the program doesn't compile!)