module Prelude.Functor where

open import Prelude.Init

{-
Functor : (Set ℓ → Set ℓ) → Set (lsuc ℓ)
Functor {ℓ = ℓ} = RawFunctor {ℓ = ℓ} {ℓ′ = ℓ}
open RawFunctor ⦃ ... ⦄ public
-}

private variable A B C : Set 

record Functor (F : Set↑) : Setω where
  infixl 4 _<$>_ _<$_
  infixl 1 _<&>_

  field _<$>_ : (A  B)  F A  F B
  fmap = _<$>_

  _<$_ : A  F B  F A
  x <$ y = const x <$> y

  _<&>_ : F A  (A  B)  F B
  _<&>_ = flip _<$>_
open Functor ⦃...⦄ public

record FunctorLaws (F : Set↑)  _ : Functor F  : Setω where
  field
    -- preserves identity morphisms
    fmap-id :  {A : Set } (x : F A) 
      fmap id x  x
    -- preserves composition of morphisms
    fmap-∘  :  {A : Set } {B : Set ℓ′} {C : Set ℓ″} {f : B  C} {g : A  B} (x : F A) 
      fmap (f  g) x  (fmap f  fmap g) x
open FunctorLaws ⦃...⦄ public

-- Id : Set↑
-- Id x = x

instance
  -- Functor-Id : Functor Id
  -- Functor-Id ._<$>_ f x = f x

  Functor-Maybe : Functor Maybe
  Functor-Maybe ._<$>_ = M.map

  FunctorLaws-Maybe : FunctorLaws Maybe
  FunctorLaws-Maybe = λ where
    .fmap-id  λ where (just _)  refl; nothing  refl
    .fmap-∘   λ where (just _)  refl; nothing  refl

  Functor-List : Functor List
  Functor-List ._<$>_ = L.map

  FunctorLaws-List : FunctorLaws List
  FunctorLaws-List = record {fmap-id = p; fmap-∘ = q}
    where
      p :  {A : Set } (x : List A)  fmap id x  x
      p = λ where
        []  refl
        (x  xs)  cong (x ∷_) (p xs)

      q :  {A : Set } {B : Set ℓ′} {C : Set ℓ″} {f : B  C} {g : A  B} (x : List A) 
        fmap (f  g) x  (fmap f  fmap g) x
      q {f = f}{g} = λ where
        []  refl
        (x  xs)  cong (f (g x) ∷_) (q xs)

  Functor-List⁺ : Functor List⁺
  Functor-List⁺ ._<$>_ = L.NE.map

  Functor-Vec :  {n}  Functor (flip Vec n)
  Functor-Vec ._<$>_ = V.map

  Functor-TC : Functor Meta.TC
  Functor-TC = record {R}
    where import Reflection.TypeChecking.Monad.Syntax as R

  Functor-Abs : Functor  Meta.Abs
  Functor-Abs = record {R}
    where import Reflection.Abstraction as R renaming (map to _<$>_)

  Functor-Arg : Functor Meta.Arg
  Functor-Arg = record {R}
    where import Reflection.Argument as R renaming (map to _<$>_)

  Functor-∃Vec : Functor (  Vec)
  Functor-∃Vec ._<$>_ f (_ , xs) = -, (f <$> xs)

private
  _ : fmap suc (just 0)  just 1
  _ = refl

  _ : fmap suc (List   0  1  2  [])  (1  2  3  [])
  _ = refl

  _ : fmap suc (List⁺   0  1  2  [])  (1  2  3  [])
  _ = refl

  _ : fmap suc (Vec  3  0  1  2  [])  (1  2  3  [])
  _ = refl

  _ : fmap suc ( (Vec )  -, 0  1  2  [])  (-, 1  2  3  [])
  _ = refl