packages feed

raw-feldspar-0.1: examples/Tut7_ImperativeProgramming.hs

{-# LANGUAGE QuasiQuotes #-}

module Tut7_ImperativeProgramming where

-- This file demonstrates
--
-- * Imperative programming using loops, references and mutable arrays
-- * FFI: Binding to external C libraries
-- * Including C definitions

-- TODO Add example with mutable arrays.

import qualified Prelude

import Feldspar.Run

import Tut2_ExpressionsAndTypes (fib)



--------------------------------------------------------------------------------

printFib :: Run ()
printFib = do
    printf "Enter a positive number: "
    n <- readStd
    printf "The %dth Fibonacci number is %d.\n" n (fib n)

-- Note that `printf` accepts a variable number of arguments (like the `printf`
-- in normal Haskell).



--------------------------------------------------------------------------------

-- Demonstration of mutable references and while-loops.

sumInput :: Run ()
sumInput = do
    done <- initRef false
    sum  <- initRef (0 :: Data Word32)
    while (not <$> getRef done) $ do
        printf "Enter a number (0 means done): "
        n <- readStd
        iff (n == 0)
          (setRef done true)
          (modifyRef sum (+n))
    s <- getRef sum
    printf "The sum of your numbers is %d.\n" s



--------------------------------------------------------------------------------

-- Binding to external C libraries:

abort :: Run ()
abort = do
    addInclude "<stdlib.h>"
    callProc "abort" []

-- It possible to add C functions to the generated code and use `callProc` to
-- call them:

printRef :: DRef Word32 -> Run ()
printRef s = do
    addInclude "<stdio.h>"
    addDefinition printRef_def
    callProc "printRef" [refArg s]
  where
    printRef_def = [cedecl|
        void printRef (typename uint32_t * s) {
            printf ("The value of the reference is %d.\n", *s);
        }
        |]

test_printRef = do
    r <- initRef (22 :: Data Word32)
    printRef r

-- Note that code using `addDefinition`, `callProc` etc. cannot be run using
-- `runIO`.



--------------------------------------------------------------------------------

testAll = do
    compareCompiled printFib (runIO printFib) "7\n"
    compareCompiled sumInput (runIO sumInput) (Prelude.unlines $ Prelude.map show $ Prelude.reverse [0..20])
    icompile abort
    icompile test_printRef
    compareCompiled test_printRef (putStrLn "The value of the reference is 22.") ""