packages feed

code-conjure-0.3.2: src/Conjure/Constructors.hs

-- |
-- Module      : Conjure.Constructors
-- Copyright   : (c) 2021 Rudy Matela
-- License     : 3-Clause BSD  (see the file LICENSE)
-- Maintainer  : Rudy Matela <rudy@matela.com.br>
--
-- This module is part of 'Conjure'.
--
-- This module defines the 'Constructors' typeclass
-- that allows listing constructors of a type
-- encoded as 'Expr's
--
-- You are probably better off importing "Conjure".
{-# Language DeriveDataTypeable, StandaloneDeriving #-} -- for GHC < 7.10
module Conjure.Constructors
  ( Constructors (..)
  , Fxpr
  , Fxpress (..)
  , sumFxpr
  , factFxpr
  , nullFxpr
  , isZeroFxpr
  )
where

import Conjure.Utils
import Data.Express
import Data.Express.Express
import Data.Express.Fixtures
import Data.Typeable (Typeable)

type Fxpr  =  [([Expr],Expr)]

sumFxpr :: Fxpr
sumFxpr  =
  [ [nil]           =-  zero
  , [(xx -:- xxs)]  =-  xx -+- (var "recurse" (undefined :: [Int] -> Int) :$ xxs)
  ]
  where
  (=-) = (,)
  infixr 0 =-

factFxpr :: Fxpr
factFxpr  =  undefined

nullFxpr :: Fxpr
nullFxpr  =
  [ [nil]          =- false
  , [(xx -:- xxs)] =- false
  ]
  where
  (=-) = (,)
  infixr 0 =-

isZeroFxpr :: Fxpr
isZeroFxpr  =
  [ [zero]  =- true
  , [inc xx] =- false
  ]
  where
  inc = undefined -- TODO: define me
  (=-) = (,)
  infixr 0 =-


class Typeable a => Fxpress a where
  fvl :: Fxpr -> a
  fvl (([],e):_)  =  evl e
  fvl _           =  error "fvl: incomplete pattern match"

instance Fxpress ()
instance Fxpress Int
instance Fxpress Bool
instance Fxpress Char
instance Fxpress a => Fxpress [a]
instance Fxpress a => Fxpress (Maybe a)
instance (Fxpress a, Fxpress b) => Fxpress (Either a b)

instance (Constructors a, Fxpress b) => Fxpress (a -> b) where
  fvl cs x  =  fvl [ (ps,exp //- bs)
                   | (p:ps,exp) <- cs
                   , bs <- maybeToList (match (expr1 x) p)
                   ]
-- TODO: add support for recursion


class Express a => Constructors a where
  expr1 :: a -> Expr
  constructors :: a -> [Expr]

instance Constructors () where
  expr1  =  val
  constructors _  =  [val ()]

instance Constructors Bool where
  expr1  =  val
  constructors _  =  [val False, val True]

constructorsNum :: (Num a, Express a) => a -> [Expr]
constructorsNum x  =  [ hole x -- <= 0 -- val (0 -: x)
                      , value "inc" ((+1) ->: x) :$ hole x
                      ]

expr1Num :: (Ord a, Num a, Express a) => a -> Expr
expr1Num x
  | x <= 0     =  val x
  | otherwise  =  value "inc" ((+1) ->: x) :$ val (x-1)

instance Constructors Int where
  expr1  =  expr1Num
  constructors  =  constructorsNum

instance Constructors Integer where
  expr1  =  expr1Num
  constructors  =  constructorsNum

instance Constructors Char where
  expr1  =  val
  constructors _  =  []

instance Express a => Constructors [a] where
  expr1 xs  =  case xs of
               [] -> val xs
               (y:ys) -> value ":" ((:) ->>: xs) :$ val y :$ val ys
  constructors xs  =  [ val ([] -: xs)
                      , value ":" ((:) ->>: xs) :$ hole x :$ hole xs
                      ]
    where
    x  =  head xs


instance (Express a, Express b) => Constructors (a,b) where
  expr1 (x,y)  =  value "," ((,) ->>: (x,y))
               :$ val x :$ val y
  constructors xy  =  [value "," ((,) ->>: xy) :$ hole x :$ hole y]
    where
    (x,y) = (undefined,undefined) -: xy

instance (Express a, Express b, Express c) => Constructors (a,b,c) where
  expr1 (x,y,z)  =  value ",," ((,,) ->>>: (x,y,z))
                 :$ val x :$ val y :$ val z

  constructors xyz  =  [value ",," ((,,) ->>>: xyz) :$ hole x :$ hole y :$ hole z]
    where
    (x,y,z) = (undefined,undefined,undefined) -: xyz

instance Express a => Constructors (Maybe a) where
  expr1 mx@Nothing   =  value "Nothing" (Nothing -: mx)
  expr1 mx@(Just x)  =  value "Just"    (Just   ->: mx) :$ val x
  constructors mx  =  [ value "Nothing" (Nothing -: mx)
                      , value "Just" (Just ->: mx) :$ hole x
                      ]
    where
    x  =  Just undefined -: mx


instance (Express a, Express b) => Constructors (Either a b) where
  expr1 lx@(Left x)   =  value "Left"  (Left  ->: lx) :$ val x
  expr1 ry@(Right y)  =  value "Right" (Right ->: ry) :$ val y
  constructors exy  =  [ value "Left" (Left ->: exy) :$ hole x
                       , value "Right" (Right ->: exy) :$ hole y
                       ]
    where
    x  =  Left undefined -: exy
    y  =  Right undefined -: exy