module Stdlib.Data.Pair;

import Stdlib.Data.Pair.Base open public;
import Stdlib.Data.Bool.Base open;
import Stdlib.Data.String.Base open;

import Stdlib.Trait.Eq open;
import Stdlib.Trait.Ord open;
import Stdlib.Trait.Show open;

{-# specialize: true, inline: case #-}
instance
eqProductI {A B} : {{Eq A}} -> {{Eq B}} -> Eq (Pair A B)
  | {{mkEq eqA}} {{mkEq eqB}} :=
    mkEq@{
      eq (p1 p2 : Pair A B) : Bool :=
        case p1, p2 of (a1, b1), a2, b2 := eqA a1 a2 && eqB b1 b2;
    };

{-# specialize: true, inline: case #-}
instance
ordProductI {A B} : {{Ord A}} -> {{Ord B}} -> Ord (Pair A B)
  | {{mkOrd cmpA}} {{mkOrd cmpB}} :=
    mkOrd@{
      cmp (p1 p2 : Pair A B) : Ordering :=
        case p1, p2 of
          (a1, b1), a2, b2 :=
            case cmpA a1 a2 of
              | LessThan := LessThan
              | GreaterThan := GreaterThan
              | Equal := cmpB b1 b2;
    };

instance
showProductI {A B} : {{Show A}} -> {{Show B}} -> Show (Pair A B)
  | {{mkShow showA}} {{mkShow showB}} :=
    mkShow@{
      show (p : Pair A B) : String :=
        case p of a, b := "(" ++str showA a ++str " , " ++str showB b ++str ")";
    };