Skip to content

Commit b38a830

Browse files
author
Thomas Mahler
committed
got the termReducer working
1 parent 8ebefe9 commit b38a830

4 files changed

Lines changed: 136 additions & 54 deletions

File tree

app/Eval.hs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
module Eval (evalLine, main) where
2+
3+
-- import qualified Prelude() --; import MHSPrelude
4+
import Control.Exception
5+
import MicroHs.Compile
6+
import MicroHs.CompileCache
7+
import MicroHs.Desugar(LDef)
8+
import MicroHs.Exp
9+
import MicroHs.Expr
10+
import MicroHs.Flags
11+
import MicroHs.Ident(mkIdent, qualIdent)
12+
import qualified MicroHs.IdentMap as M
13+
import MicroHs.Parse
14+
import MicroHs.StateIO
15+
import MicroHs.SymTab(stEmpty)
16+
import MicroHs.Translate
17+
import MicroHs.TCMonad(TCState(..))
18+
import MicroHs.TypeCheck(TModule(..), Symbols)
19+
import MhsEval (withMhsContext, eval, run)
20+
import MicroHs.ExpPrint (toStringCMdl)
21+
import Unsafe.Coerce
22+
import System.IO
23+
24+
-- This function evaluates a line of Haskell code and
25+
-- returns the result.
26+
evalLine :: forall a. String -> IO a
27+
evalLine line = do
28+
dir <- getMhsDir
29+
-- Set up initial flags and cache
30+
let flags = defaultFlags dir
31+
--flags = defs { interactive = True, verbose = 0 }
32+
cache <- getCached flags
33+
34+
-- Create module with preamble and the expression to evaluate
35+
let preamble = "module Interactive where\n"
36+
-- ++ "import Prelude\n"
37+
-- ++ "default Num (Integer, Double)\n"
38+
-- ++ "default IsString (String)\n"
39+
-- ++ "default Show (())\n"
40+
41+
itName = "_it"
42+
itIOName = "_itIO"
43+
44+
-- Wrap the expression to make it evaluable
45+
mkIt l = itName ++ " = " ++ l ++ "\n"
46+
--mkItIO l = mkIt l ++ itIOName ++ " = show $ " ++ itName ++ "\n"
47+
48+
-- Combine preamble with the wrapped expression
49+
moduleStr = preamble ++ "\n" ++ mkIt line
50+
51+
-- Parse the module
52+
let mdl = parseDie pTopModule "" moduleStr
53+
54+
-- Compile the module
55+
((dmdl, _, _), _) <- runStateIO (compileInteractive flags mdl) cache
56+
tmod <- evaluate $ compileToCombinators dmdl
57+
let allDefs = tBindingsOf tmod
58+
59+
let rmn = mkIdent "Interactive"
60+
mainName = qualIdent rmn (mkIdent itName)
61+
cmdl = (allDefs, if noLink flags then Lit (LInt 0) else Var mainName)
62+
(numOutDefs, forExps, prg) = toStringCMdl cmdl
63+
64+
65+
putStrLn $ "Compiled program:\n" ++ prg
66+
-- Execute the compiled expression
67+
result <- withMhsContext $ \ctx ->
68+
eval ctx prg
69+
putStrLn $ "Result: " ++ result
70+
return (unsafeCoerce result :: a)
71+
72+
73+
74+
75+
main :: IO ()
76+
main = do
77+
let input = "1 + 2 * 3" -- Example input
78+
result <- evalLine input :: IO Int
79+
print result

lambda-ski.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ executable benchmark
7575
executable lambda-ski-exe
7676
main-is: Main.hs
7777
other-modules:
78+
Eval
7879
Paths_lambda_ski
7980
hs-source-dirs:
8081
app

src/TermReducer.hs

Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,81 @@
11
module TermReducer where
22

3-
import Data.Generics.Uniplate.Data
3+
import Data.Generics.Uniplate.Data
44
import CLTerm
5-
import Debug.Trace
65

7-
-- reduce :: Exp -> Exp
8-
-- reduce (((S :@ x) :@ y) :@ z) = (x :@ z) :@ (y :@ z)
9-
-- reduce ((((S' :@ x) :@ y) :@ z) :@ w) = (x :@ (y :@ w)) :@ (z :@ w)
10-
-- reduce ((K :@ x) :@ _y) = x
11-
-- reduce ((A :@ _x) :@ y) = y
12-
-- reduce ((U :@ x) :@ y) = y :@ x
13-
-- reduce (I :@ x) = x
14-
-- reduce (((B :@ x) :@ y) :@ z) = x :@ (y :@ z)
15-
-- reduce ((((B' :@ x) :@ y) :@ z) :@ w) = (x :@ y) :@ (z :@ w)
16-
-- reduce (((Z :@ x) :@ y) :@ _z) = x :@ y
17-
-- reduce (((C :@ x) :@ y) :@ z) = (x :@ z) :@ y
18-
-- reduce ((((C' :@ x) :@ y) :@ z) :@ w) = (x :@ (y :@ w)) :@ z
19-
-- reduce (((P :@ x) :@ y) :@ z) = (z :@ x) :@ y
20-
-- reduce (((R :@ x) :@ y) :@ z) = (y :@ z) :@ x
21-
-- reduce ((((O :@ x) :@ y) :@ z) :@ w) = (w :@ x) :@ y
22-
-- reduce (((K2 :@ x) :@ _y) :@ _z) = x
23-
-- reduce ((((K3 :@ x) :@ _y) :@ _z) :@ _w) = x
24-
-- reduce (((((K4 :@ x) :@ _y) :@ _z) :@ _w) :@ _v) = x
25-
-- reduce ((((C'B :@ x) :@ y) :@ z) :@ w) = (x :@ z) :@ (y :@ w)
26-
-- reduce (Label _ e) = e
27-
-- reduce (Tick _ :@ e) = e
28-
-- reduce e = e
296

307
-- | Single step reduction - reduces only the outermost redex
318
reduceStep :: CL -> CL
329
reduceStep (Com c) = Com c
3310
reduceStep (INT i) = INT i
3411
reduceStep (Com I :@ t) = t
35-
reduceStep (Com K :@ t :@ u) = t
36-
reduceStep (Com S :@ x :@ y :@ z) = (x :@ z) :@ (y :@ z)
37-
reduceStep (Com B :@ f :@ g :@ x) = f :@ (g :@ x) -- B F G X = F (G X)
38-
reduceStep (Com C :@ x :@ y :@ z) = x :@ z :@ y
39-
reduceStep yt@(Com Y :@ t) = t :@ yt
40-
reduceStep (Com P :@ t :@ u) = Com P :@ t :@ u
41-
reduceStep (Com R :@ t :@ u) = Com R :@ t :@ u
42-
reduceStep (Com ADD :@ INT i :@ INT j) = INT (i + j)
43-
reduceStep (Com SUB :@ INT i :@ INT j) = INT (i - j)
44-
reduceStep (Com MUL :@ INT i :@ INT j) = INT (i * j)
45-
reduceStep (Com DIV :@ INT i :@ INT j) = INT (i `div` j)
46-
reduceStep (Com REM :@ INT i :@ INT j) = INT (i `rem` j)
12+
reduceStep ((Com K :@ t) :@ u) = t
13+
reduceStep (((Com S :@ x) :@ y) :@ z) = (x :@ z) :@ (y :@ z)
14+
reduceStep (((Com B :@ f) :@ g) :@ x) = f :@ (g :@ x) -- B F G X = F (G X)
15+
reduceStep (((Com C :@ x) :@ y) :@ z) = x :@ z :@ y
16+
-- Y combinator: expand only when it's applied to something
17+
-- Y f x should reduce to f (Y f) x, not Y f should reduce to f (Y f)
18+
reduceStep ((Com Y :@ f) :@ x) = (f :@ (Com Y :@ f)) :@ x
19+
--reduceStep (Com Y :@ t) = Com Y :@ t -- Don't expand Y on its own
20+
reduceStep ((Com P :@ t) :@ u) = (Com P :@ t) :@ u -- P doesn't reduce
21+
-- R takes 3 arguments: R F G X = G X F
22+
reduceStep (((Com R :@ f) :@ g) :@ x) = (g :@ x) :@ f
23+
reduceStep ((Com ADD :@ INT i) :@ INT j) = INT (i + j)
24+
reduceStep ((Com SUB :@ INT i) :@ INT j) = INT (i - j)
25+
reduceStep ((Com MUL :@ INT i) :@ INT j) = INT (i * j)
26+
reduceStep ((Com DIV :@ INT i) :@ INT j) = INT (i `div` j)
27+
reduceStep ((Com REM :@ INT i) :@ INT j) = INT (i `rem` j)
4728
reduceStep (Com SUB1 :@ INT i) = INT (i - 1)
48-
reduceStep (Com EQL :@ INT i :@ INT j) = if i == j then trueCL else falseCL
49-
reduceStep (Com GEQ :@ INT i :@ INT j) = if i >= j then trueCL else falseCL
29+
reduceStep ((Com EQL :@ INT i) :@ INT j) = if i == j then trueCL else falseCL
30+
reduceStep ((Com GEQ :@ INT i) :@ INT j) = if i >= j then trueCL else falseCL
5031
reduceStep (Com ZEROP :@ INT i) = if i == 0 then trueCL else falseCL
51-
reduceStep (Com ZEROP :@ i) = Com ZEROP :@ (reduce i) -- Keep ZEROP combinator for non-integer terms
52-
reduceStep (Com B' :@ t :@ u :@ v) = t :@ (u :@ v)
53-
reduceStep (Com C' :@ t :@ u :@ v) = t :@ v :@ u
54-
reduceStep (Com S' :@ t :@ u :@ v) = (t :@ v) :@ (u :@ v)
32+
reduceStep (Com ZEROP :@ i) = Com ZEROP :@ reduceStep i -- Reduce argument without calling full reduce
33+
-- B' takes 4 arguments: B' P Q R S = P Q (R S)
34+
reduceStep ((((Com B' :@ p) :@ q) :@ r) :@ s) = (p :@ q) :@ (r :@ s)
35+
-- C' takes 4 arguments: C' P Q R S = P (Q S) R
36+
reduceStep ((((Com C' :@ p) :@ q) :@ r) :@ s) = (p :@ (q :@ s)) :@ r
37+
-- S' takes 4 arguments: S' P Q R S = P (Q S) (R S)
38+
reduceStep ((((Com S' :@ p) :@ q) :@ r) :@ s) = (p :@ (q :@ s)) :@ (r :@ s)
5539
reduceStep (Com T :@ t) = t
56-
reduceStep (Com A :@ x :@ y) = y -- A combinator: λx y. y (like FALSE)
57-
-- For partial applications, try to reduce arguments
58-
reduceStep (f :@ x) =
59-
let f' = reduce f
60-
in if f' == f
61-
then f :@ reduceStep x -- Only reduce argument if function can't be reduced
62-
else f' :@ x -- Apply reduction to function first
40+
reduceStep ((Com A :@ x) :@ y) = y -- A combinator: λx y. y (like TRUE, selects second)
41+
-- For partial applications, don't reduce recursively in reduceStep
42+
reduceStep (f :@ x) = f :@ x -- No reduction for general applications
6343
reduceStep x = x
6444

65-
-- | Reduce with step limit to avoid infinite loops
45+
-- | Reduce with step limit using leftmost-outermost strategy
6646
reduceWithLimit :: Int -> CL -> CL
6747
reduceWithLimit 0 x = x
6848
reduceWithLimit n x =
69-
let x' = reduceStep (trace (show x) x)
49+
let x' = reduceOnce x
7050
in if x' == x
7151
then x -- Normal form reached
7252
else reduceWithLimit (n-1) x'
7353

54+
-- | Perform one reduction step using leftmost-outermost strategy
55+
reduceOnce :: CL -> CL
56+
reduceOnce term =
57+
-- First try direct reduction at the top level
58+
let stepped = reduceStep term
59+
in if stepped /= term
60+
then stepped -- A reduction happened at the top level
61+
else case term of
62+
-- For applications, use leftmost-outermost strategy
63+
f :@ x ->
64+
-- Try to reduce f first (leftmost)
65+
let f' = reduceOnce f
66+
in if f' /= f
67+
then f' :@ x -- If f reduced, keep x unchanged
68+
else
69+
-- If f didn't reduce, try to reduce x
70+
let x' = reduceOnce x
71+
in if x' /= x
72+
then f :@ x'
73+
else term -- Nothing can be reduced
74+
_ -> term -- No reduction possible
75+
7476
-- | Original reduce function - now with step limit
7577
reduce :: CL -> CL
76-
reduce = reduceWithLimit 50 -- Allow up to 50 reduction steps
78+
reduce = reduceWithLimit 1000 -- Increased limit for recursive functions
7779

7880
-- | Deep reduction using transform (original approach)
7981
redDeep :: CL -> CL

test/TermReducerSpec.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ spec = do
4444
verify simpleComposition
4545
it "computes a simple If statement" $
4646
verify simpleIf
47-
-- it "computes simple fac (recursive)" $
48-
-- verify smallFactorial
47+
it "computes simple fac (recursive)" $
48+
verify smallFactorial
4949

5050
-- Very simple non-recursive tests for TermReducer
5151
simpleConstant :: String

0 commit comments

Comments
 (0)