packages feed

purescript-0.15.15: tests/purs/passing/TCOMutRec.purs

module Main where

import Prelude
import Effect (Effect)
import Effect.Console (log)
import Test.Assert (assertEqual, assertThrows)

tco1 :: Int -> Int
tco1 = f 0
  where
  f x y = g (x + 2) (y - 1)
    where
    g x' y' = if y' <= 0 then x' else f x' y'

tco2 :: Int -> Int
tco2 = f 0
  where
  f x y = g (x + 2) (y - 1)
    where
    g x' y' = h (y' <= 0) x' y'
    h test x' y' = if test then x' else f x' y'

tco3 :: Int -> Int
tco3 y0 = f 0 y0
  where
  f x y = g x (h y)
    where
    g x' y' =
      if y' <= 0 then x'
      else if y' > y0 / 2 then g (j x') (y' - 1)
      else f (x' + 2) y'
    h y = y - 1
  j x = x + 3

tco4 :: Int -> Int
tco4 = f 0
  where
  f x y = if y <= 0 then x else g (y - 1)
    where
    g y' = f (x + 2) y'

-- The following examples are functions which are prevented from being TCO'd
-- because the arity of the function being looped does not match the function
-- call. In theory, these could be made to optimize via eta-expansion in the
-- future, in which case the assertions can change.

ntco1 :: Int -> Int
ntco1 y0 = f 0 y0
  where
  f x = if x > 10 * y0 then (x + _) else g x
    where
    g x' y' = f (x' + 10) (y' - 1)

ntco2 :: Int -> Int
ntco2 = f 0
  where
  f x y = if y <= 0 then x else g x (y - 1)
    where
    g x' = f (x' + 2)

ntco3 :: Int -> Int
ntco3 = f 0
  where
  f x y = if y <= 0 then x else g (y - 1)
    where
    g = f (x + 2)

ntco4 :: Int -> Int
ntco4 = f 0
  where
  f x y = if y <= 0 then x else g (y - 1)
    where
    g = h x
    h x' y' = f (x' + 2) y'

main :: Effect Unit
main = do
  assertEqual { expected: 200000, actual: tco1 100000 }
  assertEqual { expected: 200000, actual: tco2 100000 }
  assertEqual { expected: 249997, actual: tco3 100000 }
  assertEqual { expected: 200000, actual: tco4 100000 }

  assertEqual { expected: 1009, actual: ntco1 100 }
  assertThrows \_ -> ntco1 100000

  assertEqual { expected: 200, actual: ntco2 100 }
  assertThrows \_ -> ntco2 100000

  assertEqual { expected: 200, actual: ntco3 100 }
  assertThrows \_ -> ntco3 100000

  assertEqual { expected: 200, actual: ntco4 100 }
  assertThrows \_ -> ntco4 100000

  log "Done"