{-# LANGUAGE RankNTypes, KindSignatures, BangPatterns, GADTs #-}

{-|
Module      : Language.LambdaBase.Core
Description : The core dataTypes of the language
-}
module Language.LambdaBase.Core where

import Data.List

-- | Evaluation scheme, Lazy or Strict
data EVS = Lazy | Strict deriving (Show, Eq)

-- | Lambda argument
data Arg = Arg !String !EVS deriving (Show, Eq)

{-|
Infix / Prefix / LateInfix

The LateInfix is a trick used is the eval function.
-}
data Fix = Infix | Prefix | LateInfix deriving (Eq,Show)

{-|
A name is a 'to be' literal
In a programme, foo can be a name ( if it is not a lambda argument ). "foo" is also a name but is delimited by double quotes.
-}
data NameType =
    Naked
  | Delimited String String
  deriving (Eq,Show)

{-|
An expression of host language a.
-}
data Expr a =
    Lambda !Arg !(Expr a) !Fix
  | Expr ![Expr a] !Fix
  | Name !String !NameType !Fix
  | Lit !a !Fix

{-|
Crappy show instance ;(
-}
instance (Show a) => Show (Expr a) where
    show (Lambda (Arg a _) e _)       = "(\\"++a++" -> \n"++(show e)++")"
    show (Expr l Prefix)              = "(" ++ ( concat ( intersperse " \n " . map (show) $ l ) ) ++ ")"
    show (Expr l Infix)               = "`(" ++ ( concat ( intersperse " \n " . map (show) $ l ) ) ++ ")`"
    show (Name x Naked _)             = x
    show (Name x (Delimited d1 d2) _) = d1 ++ x ++ d2
    show (Lit a f)                    = show a
{-|
The Lit class is for the language contained inside lambdaBase.

toLit sould take a Name and transform it to a literal of its language.

apply is for function application.

A programme

> add 123 321

will be evaluated by transforming add to a literal.

Transforming 123 to a literal.

Partially apply add and 123 with the apply function.

Transforming 321 to a literal.

Apply the "add123" literal and the 321 literal.

And if the Lit instance is correct, the result should be a 444 literal.

See lambdaLit for an example of a Lit instance.
-}
class Lit a where
    apply :: a -> a -> Expr a
    fromExpr :: Expr a -> a
    toLit :: Expr a -> Maybe a
    getEVS :: a -> EVS