module 1Lab.Type.Pi.Currying whereCurrying and uncurrying automationπ
This module contains proof automation for passing between curried and uncurried Ξ types.
Curryingπ
The core of our currying automation is the following typeclass, which decomposes a type into a Ξ type.
record Curried {β} (A : Type β) (βd βf : Level) : Type (β β lsuc βd β lsuc βf) where
  no-eta-equality
  field
    Dom : Type βd
    Cod : Dom β Type βf
    eqv : ((d : Dom) β Cod d) β AThe only interesting instances of Curried check to see
if
is an iterated Ξ  type, and shuffle over elements of the codomain into a
Ξ£ in the domain.
instance
  Curried-Ξ 
    : β {β β' β'' βd βf} {A : Type β} {B : A β Type β'} {C : (a : A) β B a β Type β''}
    β β¦ _ : β {a} β Curried ((b : B a) β C a b) βd βf β¦
    β Curried ((a : A) (b : B a) β C a b) (βd β β) βf
  Curried-Ξ  {A = A} β¦ c β¦ .Curried.Dom = Ξ£[ a β A ] (Curried.Dom (c {a}))
  Curried-Ξ  {A = A} β¦ c β¦ .Curried.Cod (a , d) = Curried.Cod c d
  Curried-Ξ  {A = A} β¦ c β¦ .Curried.eqv = curryβ βe Ξ -ap-cod Ξ» a β Curried.eqv c
  Curried-Ξ '
    : β {β β' β'' βd βf} {A : Type β} {B : A β Type β'} {C : (a : A) β B a β Type β''}
    β β¦ _ : β {a} β Curried ((b : B a) β C a b) βd βf β¦
    β Curried ({a : A} (b : B a) β C a b) (βd β β) βf
  Curried-Ξ ' {A = A} β¦ c β¦ .Curried.Dom = Ξ£[ a β A ] (Curried.Dom (c {a}))
  Curried-Ξ ' {A = A} β¦ c β¦ .Curried.Cod (a , d) = Curried.Cod c d
  Curried-Ξ ' {A = A} β¦ c β¦ .Curried.eqv = curryβ βe Ξ -implβ βe Ξ '-ap-cod Ξ» a β Curried.eqv cFinally, we have an INCOHERENT base case that will match
only when we have run out of iterated Ξ  types.
  Curried-default
    : β {β β'} {A : Type β} {B : A β Type β'}
    β Curried ((a : A) β B a) β β'
  Curried-default {A = A} {B = B} .Curried.Dom = A
  Curried-default {A = A} {B = B} .Curried.Cod = B
  Curried-default {A = A} {B = B} .Curried.eqv = idβ
  {-# INCOHERENT Curried-default #-}Now that weβve got our instances in place, we can use instance arguments to compute the fully curried version of a type.
Curry : β {β βd βf} β (A : Type β) β β¦ C : Curried A βd βf β¦ β Type (βd β βf)
Curry A β¦ C β¦ = (x : Curried.Dom C) β Curried.Cod C x
{-# NOINLINE Curry #-}We also expose the equivlance between the original type and itβs curried form.
curry!
  : β {β βd βf}
  β {A : Type β}
  β β¦ C : Curried A βd βf β¦
  β A β Curry A
curry! β¦ C β¦ = Curried.eqv C eβ»ΒΉ
{-# NOINLINE curry! #-}Uncurryingπ
The uncurrying typeclass is identical to the currying typeclass in all but name.
record Uncurried {β} (A : Type β) (βd βf : Level) : Type (β β lsuc βd β lsuc βf) where
  no-eta-equality
  field
    Dom : Type βd
    Cod : Dom β Type βf
    eqv : ((d : Dom) β Cod d) β AHowever, the instances for Uncurried go in the opposite
direction.
instance
  Uncurried-Ξ 
    : β {β β' β'' βd βf} {A : Type β} {B : A β Type β'} {C : Ξ£ A B β Type β''}
    β β¦ _ : β {a} β Uncurried ((b : B a) β C (a , b)) βd βf β¦
    β Uncurried ((ab : Ξ£ A B) β C ab) β (βd β βf)
  Uncurried-Ξ  {A = A} β¦ c β¦ .Uncurried.Dom = A
  Uncurried-Ξ  {A = A} β¦ c β¦ .Uncurried.Cod a = (d : Uncurried.Dom (c {a})) β Uncurried.Cod (c {a}) d
  Uncurried-Ξ  {A = A} β¦ c β¦ .Uncurried.eqv = Ξ -ap-cod (Ξ» a β Uncurried.eqv c) βe curryβ eβ»ΒΉ
  Uncurried-default
    : β {β β'} {A : Type β} {B : A β Type β'}
    β Uncurried ((a : A) β B a) β β'
  Uncurried-default {A = A} {B = B} .Uncurried.Dom = A
  Uncurried-default {A = A} {B = B} .Uncurried.Cod = B
  Uncurried-default {A = A} {B = B} .Uncurried.eqv = idβWe expose a similar API for uncurrying.
Uncurry : β {β βd βf} β (A : Type β) β β¦ C : Uncurried A βd βf β¦ β Type (βd β βf)
Uncurry A β¦ C β¦ = (x : Uncurried.Dom C) β Uncurried.Cod C x
{-# NOINLINE Uncurry #-}
uncurry!
  : β {β βd βf}
  β {A : Type β}
  β β¦ C : Uncurried A βd βf β¦
  β A β Uncurry A
uncurry! β¦ C β¦ = Uncurried.eqv C eβ»ΒΉ
{-# NOINLINE uncurry! #-}