Brainfunct

Brainfunct is a functional esoteric programming language based on brainfuck, created by User:Koen in 2012 when he observed a lack of functional languages among the plethora of Brainfuck derivatives. A program in brainfunct consists in a succession of declaration of functions. Functions have no name but have a number, corresponding to the order in which they are declared. Functions operates on a tape similar to brainfuck's. The commands are:

Function declaration
There are two versions of Brainfunct. The only difference is the syntax for function declaration.

Brainfunct-slash
In brainfunct-slash, functions are simply separated by the symbol. The first function is number 1. The last function is the main function; it cannot be called by other functions, but it is called when the execution starts.

Brainfunct-nested
The great addition of brainfunct-nested is the use of parenthesizing instead of the simple. This allows for nested functions. Nested functions cannot be called from out of the function where they are declared. The number of a function is the smallest number available within their scope, starting with less deep functions. All commands not included in a function are part of the main function. The following is an example of how functions are numbered in this version: (1) (2) (((7)6)3) (4) (((8)6)(7)5) main

Truth-machine
////////////////////////////////////////////////.@/,.@ In this program the first 48 functions are no-ops, and the 49th (49 being the ASCII code for '1') is an infinite loop of printing character '1'.

Cat program
>,.<@/+@ Doesn't handle end of file. The implementation below doesn't either, though.

Syntactic sugar
To avoid "flooding" a program with the symbol, the body of a function may be preceded by the function number. The function number must be written in octal; using this notation, the truth-machine above would become: 61.@/,.@

Ocaml
Note: This interpreter supports brainfunct-slash only. let tape_size = 100;; (* ideally the tape would be unbounded *) let n_functions = 260;; (* ideally the number of functions would be unbounded *) let tape = Array.make tape_size 0;; let ptr = ref 0;; let f = Array.make n_functions "";;

let make_functions s = let i = ref 0 and j = ref 1 and l = String.length s in for k = 0 to (l - 1) do    if s.[k] = '/' then begin f.(!j) <- String.sub s !i (k - !i); i := k+1; incr j     end done; f.(0) <- String.sub s !i (l - !i);;

exception Unknown_command of char;;

let rec mtch c = match c with | '>' -> incr ptr | '<' -> decr ptr | '+' -> tape.(!ptr) <- succ tape.(!ptr) | '-' -> tape.(!ptr) <- pred tape.(!ptr) | '.' -> print_char (char_of_int tape.(!ptr)); flush(stdout) | ',' -> tape.(!ptr) <- (try int_of_char (input_char stdin) with | End_of_file -> -1) | '@' -> interpret tape.(!ptr) false | x -> raise (Unknown_command x) and interpret fn first_time = if (fn > 0 || first_time) then let l = String.length f.(fn) - 2 in   for k = 0 to l do      mtch f.(fn).[k] done; mtch f.(fn).[l + 1];;

make_functions Sys.argv.(1);;

interpret 0 true;;

Haskell
Supports both slashes and parentheses, including in weird nested combinations, essentially desugaring the former to the latter. Does not support the function number syntactic sugar. import Control.Monad.State (StateT, evalStateT, gets, liftIO, modify) import Data.Functor ((<$>), (<$)) import System.Environment (getArgs) import System.IO (hFlush, hIsEOF, hPutStr, stderr, stdin, stdout) import Text.Parsec (Parsec, between, char, choice, eof, many, parse, sepBy1, spaces, (<|>))

data Tape = Tape { left, right :: [Int] } data CmdOrFun = Cmd (FunList -> BF) | Fun (FunList -> BF) type BF = StateT Tape IO type FunList = [BF]

op :: Char -> Parsec [Char] op c = char c >> spaces

cmdOrSubfun :: Parsec [Char] CmdOrFun cmdOrSubfun = Fun <$> between (op '(') (op ')') function <|> Cmd (\funList -> findFun funList =<< getCurrent)                                       <$ op '@' <|> Cmd. const <$> choice [ modify (\(Tape ls (cur:rs)) -> Tape (cur:ls) rs)                                   <$ op '>', modify (\(Tape (l:ls) rs) -> Tape ls (l:rs))                                       <$ op '<', modify (\(Tape ls (cur:rs)) -> Tape ls (cur+1:rs))                                 <$ op '+', modify (\(Tape ls (cur:rs)) -> Tape ls (cur-1:rs))                                 <$ op '-', (getCurrent >>= \c -> liftIO $ putChar (toEnum c) >> hFlush stdout)                <$ op '.', (do c <- liftIO $ do               e <- hIsEOF stdin                if e then return (-1) else fromEnum <$> getChar            modify (\(Tape ls (_:rs)) -> Tape ls (c:rs)))                          <$ op ',' ] where getCurrent = gets (head . right) findFun fs n     | n > 0, f:_ <- drop (n-1) fs = f      | otherwise                   = return

function :: Parsec [Char] (FunList -> BF) function = makeFunction. unslash <$> sepBy1 (many cmdOrSubfun) (op '/') where unslash blocks = map (Fun . makeFunction) (init blocks) ++ last blocks makeFunction cfs funList = sequence_ [cmd funList' | Cmd cmd <- cfs] where funList' = funList ++ [fun funList' | Fun fun <- cfs]

runBF :: String -> String -> IO runBF sourceName s = case parse (between spaces eof function) sourceName s of   Left err    -> hPutStr stderr $ "Parse error: " ++ show err Right f    -> evalStateT (f []) $ Tape (repeat 0) (repeat 0)

main = runBF "command line". unwords =<< getArgs