Search code examples
haskellagdaarrow-abstraction

Haskell's Arrow-Class in Agda and -> in Agda


I have two closely related questions:

First, how can the Haskell's Arrow class be modeled / represented in Agda?

 class Arrow a where 
      arr :: (b -> c) -> a b c
      (>>>) :: a b c -> a c d -> a b d
      first :: a b c -> a (b,d) (c,d)
      second :: a b c -> a (d,b) (d,c)
      (***) :: a b c -> a b' c' -> a (b,b') (c,c')
      (&&&) :: a b c -> a b c' -> a b (c,c')

(the following Blog Post states that it should be possible...)

Second, in Haskell, the (->) is a first-class citizen and just another higher-order type and its straightforward to define (->) as one instance of the Arrow class. But how is that in Agda? I could be wrong, but I feel, that Agdas -> is a more integral part of Agda, than Haskell's -> is. So, can Agdas -> be seen as a higher-order type, i.e. a type function yielding Set which can be made an instance of Arrow?


Solution

  • Type classes are usually encoded as records in Agda, so you can encode the Arrow class as something like this:

    open import Data.Product -- for tuples
    
    record Arrow (A : Set → Set → Set) : Set₁ where
      field  
        arr    : ∀ {B C} → (B → C) → A B C
        _>>>_  : ∀ {B C D} → A B C → A C D → A B D
        first  : ∀ {B C D} → A B C → A (B × D) (C × D)
        second : ∀ {B C D} → A B C → A (D × B) (D × C)
        _***_  : ∀ {B C B' C'} → A B C → A B' C' → A (B × B') (C × C')
        _&&&_  : ∀ {B C C'} → A B C → A B C' → A B (C × C')
    

    While you can't refer to the function type directly (something like _→_ is not valid syntax), you can write your own name for it, which you can then use when writing an instance:

    _=>_ : Set → Set → Set
    A => B = A → B
    
    fnArrow : Arrow _=>_  -- Alternatively: Arrow (λ A B → (A → B)) or even Arrow _
    fnArrow = record
      { arr    = λ f → f
      ; _>>>_  = λ g f x → f (g x)
      ; first  = λ { f (x , y) → (f x , y) }
      ; second = λ { f (x , y) → (x , f y) }
      ; _***_  = λ { f g (x , y) → (f x , g y) }
      ; _&&&_  = λ f g x → (f x , g x)
      }