packages feed

ho-rewriting-0.2: examples/Feldspar.hs

{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

{-# OPTIONS_GHC -fno-warn-missing-methods #-}

module Feldspar where



import Data.Comp
import Data.Comp.Derive
import Data.Comp.Render

import Data.Rewriting.Rules
import Data.Rewriting.FirstOrder hiding (applyFirst)
import Data.Rewriting.HigherOrder

import Simple



data FORLOOP a = ForLoop a a a
  deriving (Eq, Show, Functor, Foldable, Traversable)

derive [makeEqF, makeShowF, makeShowConstr] [''FORLOOP]

instance Render FORLOOP

type Feld = VAR :+: LAM :+: APP :+: NUM :+: LOGIC :+: FORLOOP

newtype Data a = Data { unData :: Term Feld }
  deriving (Eq, Show)

instance Rep Data
  where
    type PF Data = Feld
    toRep   = Data
    fromRep = unData

type instance Var Data = Data

instance Bind Data
  where
    var = id
    lam = mkLam (Data . inject . Var . toInteger)

deriving instance Num a => Num (Data a)

class ForLoop r
  where
    forLoop_ :: r Int -> r s -> r (Int -> s -> s) -> r s

instance (Rep r, FORLOOP :<: PF r) => ForLoop r
  where
    forLoop_ len init step = toRep $ inject $ ForLoop (fromRep len) (fromRep init) (fromRep step)

forLoop :: (ForLoop r, Bind r) => r Int -> r s -> (Var r Int -> Var r s -> r s) -> r s
forLoop len init body = forLoop_ len init (lam $ \i -> lam $ \s -> body i s)

-- forLoop 0 init _  ===>  init
rule_for1 init = forLoop 0 (meta init) (\i s -> __)  ===>  meta init

-- forLoop 0 init (\i s -> s)  ===>  init
rule_for2 init = forLoop __ (meta init) (\i s -> var s)  ===>  meta init

rule_for3 len init body =
    forLoop (meta len) (meta init) (\i s -> body -$- i)
      ===>
    cond (meta len === 0) (meta init) (body -$- (meta len - 1))

rulesFeld = rules ++
    [ quantify rule_for1
    , quantify rule_for2
    , quantify rule_for3
    ]

simplify :: Data a -> Data a
simplify = Data . rewriteWith (bottomUp (applyFirst app rulesFeld)) . unData

forExample :: Data Int -> Data Int
forExample a
    = forLoop a a (\i s -> (i-i)+s)
    + forLoop a a (\i s -> i*i+100)

drawForExample  = drawTerm $ unData $ lam forExample
drawForExampleR = drawTerm $ unData $ simplify $ lam forExample

feld1 :: Data Int -> Data Int
feld1 a = a + a + 3

drawFeld1  = drawTerm $ unData $ lam feld1
drawFeld1R = drawTerm $ unData $ simplify $ lam feld1

feld2 :: Data Int
feld2 = forLoop 0 0 (+)

drawFeld2  = drawTerm $ unData feld2
drawFeld2R = drawTerm $ unData $ simplify feld2

feld3 :: Data Int -> Data Int
feld3 a = forLoop a 0 (\i s -> a+i)

drawFeld3  = drawTerm $ unData $ lam feld3
drawFeld3R = drawTerm $ unData $ simplify $ lam feld3

feld4 :: Data Int -> Data Int
feld4 a = forLoop a 0 (\i s -> a + i + s) + forLoop a 0 (\i s -> a + i + s)

drawFeld4  = drawTerm $ unData $ lam feld4
drawFeld4R = drawTerm $ unData $ simplify $ lam feld4