Real Fast Nora's Hair Salon 3: Shear Disaster Download

Real Fast Nora's Hair Salon 3: Shear Disaster Download is a functional esoteric programming language created by Nathan van Doorn in 2012. It is based on the lambda calculus.

Structure of a program
The program is a function that maps input (as a Church list of Church numerals) to output (ditto), similar to Lazy K.

All text in a program's source that is not upper-case text of the English alphabet is ignored, as this can be hard to read. The program is in reality a bunch of expressions all knotted together. There are only a handful of key words:

Lambda expressions
A lambda expression is started with the  key word. It then takes the next complete expression and wraps it in a lambda.

Numbers are what makes the lambda expression useful: A number n denotes the argument of the nth surrounding lambda expression, starting at the innermost as the 0'th.

When a lambda expression is applied to something, all the (one-more-than-)nzeros in nth level nested lambda expressions are replaced by what it has been applied to, for n&ge;0. While replacing, some numbers need to be adjusted in order to keep referring to the same argument. (These are de Bruijn indices, except zero indexed.)

An  reads the next two complete expressions, and applies the first to the second.

Possible pitfalls
An error may occur:
 * if the program begins with two consecutive lambda expressions, or equivalent, as this would require there to be more than one IO input, which is not required by an implementation;
 * if a  is not followed by a   or another  ;
 * if there are insufficient lambdas for a number expression to be fulfilled;
 * if the program ends with an uncompleted expression.

Infinite loops may occur.

Cat program
LAMBDA ZERO

Church addition excerpt
LAMBDA LAMBDA LAMBDA LAMBDA APPLY APPLY ONE MORE THAN ONE MORE THAN ONE MORE THAN ZERO ONE MORE THAN ZERO APPLY APPLY ONE MORE THAN ONE MORE THAN ZERO ONE MORE THAN ZERO ZERO

Church decrementation excerpt
LAMBDA LAMBDA LAMBDA APPLY APPLY APPLY ONE MORE THAN ONE MORE THAN ZERO LAMBDA LAMBDA APPLY ZERO APPLY ONE MORE THAN ZERO ONE MORE THAN ONE MORE THAN ONE MORE THAN ZERO LAMBDA ONE MORE THAN ZERO LAMBDA ZERO

Prime sieve
User:Tromp points out that apart from I/O, Real Fast Nora's Hair Salon 3: Shear Disaster Download is isomorphic to Binary lambda calculus by the substitutions LAMBDA=00, APPLY=01, ZERO=10, ONEMORETHAN=1 The following is his conversion of his BLC prime sieve, which also adjusts the output convention. LAMBDA APPLY LAMBDA APPLY LAMBDA APPLY LAMBDA APPLY LAMBDA APPLY ZERO APPLY ZERO APPLY APPLY LAMBDA APPLY ZERO ZERO LAMBDA LAMBDA LAMBDA APPLY APPLY ZERO LAMBDA LAMBDA APPLY ONE MORE THAN ZERO APPLY APPLY ONE MORE THAN ONE MORE THAN ONE MORE THAN ONE MORE THAN ONE MORE THAN ONE MORE THAN ZERO ONE MORE THAN ZERO ZERO APPLY LAMBDA APPLY APPLY APPLY ONE MORE THAN ONE MORE THAN ONE MORE THAN ZERO ONE MORE THAN ONE MORE THAN ONE MORE THAN ZERO ZERO APPLY LAMBDA APPLY ZERO ZERO LAMBDA APPLY ONE MORE THAN ZERO APPLY ZERO ZERO LAMBDA LAMBDA LAMBDA LAMBDA APPLY APPLY ZERO ONE MORE THAN ONE MORE THAN ZERO APPLY ONE MORE THAN ZERO APPLY ONE MORE THAN ONE MORE THAN ONE MORE THAN ONE MORE THAN ONE MORE THAN ZERO ONE MORE THAN ONE MORE THAN ONE MORE THAN ZERO LAMBDA LAMBDA LAMBDA APPLY ONE MORE THAN ONE MORE THAN ONE MORE THAN ZERO APPLY ZERO ONE MORE THAN ONE MORE THAN ZERO LAMBDA LAMBDA APPLY APPLY ZERO ONE MORE THAN ONE MORE THAN ZERO ONE MORE THAN ZERO LAMBDA APPLY ONE MORE THAN ONE MORE THAN ZERO APPLY ONE MORE THAN ZERO APPLY APPLY ONE MORE THAN ZERO ONE MORE THAN ONE MORE THAN ZERO ZERO LAMBDA LAMBDA APPLY ONE MORE THAN ZERO APPLY ONE MORE THAN ZERO APPLY ONE MORE THAN ZERO ZERO LAMBDA LAMBDA APPLY ONE MORE THAN ZERO APPLY ONE MORE THAN ZERO ZERO

Implementation
The following implementation in Haskell attempts to follow Lazy K's I/O format (except for the exit code), and probably leaks memory like a sieve due to the explicit lists of outer arguments passed.

import Control.Applicative hiding ((<|>), many) import Data.List (unfoldr) import System.Environment (getArgs) import System.IO (stdin, stdout, hSetEncoding, latin1,   hSetBuffering, BufferMode (NoBuffering)) import Text.Parsec

data WHNF a = WHNF { ann :: Maybe a, fun :: (WHNF a -> WHNF a) } type EXPR a = [WHNF a] -> WHNF a

isJunk :: Char -> Bool isJunk c = c < 'A' || c > 'Z'

junk :: Parsec String junk = skipMany $ satisfy isJunk

keyword :: String -> Parsec String keyword k = sequence_ [ char c *> junk | c <- k, not (isJunk c) ] <?> k

expr :: Int -> Parsec String (EXPR a) expr d = buildLambda <$ keyword "LAMBDA" <*> expr (d+1) <|> buildApply <$ keyword "APPLY" <*> expr d <*> expr d  <|>  buildVar <$> do        n <- try $ length <$> many (keyword "ONE MORE THAN") <* keyword "ZERO" if n < d then return n                else unexpected "number bigger than lambda nesting level"

buildLambda e env = WHNF Nothing $ \arg -> e (arg:env) buildApply e1 e2 env = fun (e1 env) (e2 env) buildVar n env = env !! n

churchToList :: WHNF a -> [WHNF a] churchToList = unfoldr (Just . churchToPair)

listToChurch :: [WHNF a] -> WHNF a listToChurch = foldr pairToChurch $ error "Only infinite lists may be converted"

churchToPair :: WHNF a -> (WHNF a, WHNF a) churchToPair (WHNF _ f)   = (f (WHNF Nothing $ \xw -> WHNF Nothing $ const xw),       f (WHNF Nothing $ \xw -> WHNF Nothing id))

pairToChurch :: WHNF a -> WHNF a -> WHNF a pairToChurch fw gw = WHNF Nothing $ \hw -> fun (fun hw fw) gw

intToChurch :: Int -> WHNF a intToChurch n   = WHNF Nothing $ \fw -> WHNF Nothing $ \xw -> iterate (fun fw) xw !! n

churchToInt :: WHNF Int -> Int churchToInt iw = case fun (fun iw $ WHNF Nothing incr) (WHNF (Just 0) v) of   WHNF (Just n) _ -> n    _               -> error $ "Output list contains non-number" where incr (WHNF mn f) = WHNF (succ <$> mn) v   v x = WHNF Nothing v

-- NB: Only characters < 256 should be in String stringToChurch :: String -> WHNF a stringToChurch s   = listToChurch $ map (intToChurch . fromEnum) s ++ repeat (intToChurch 256)

churchToString :: WHNF Int -> String churchToString = map toEnum. takeWhile (< 256). map churchToInt. churchToList

main = do   args <- getArgs (name, prog) <- case args of       [filename]      ->  filename <$> readFile filename ["-e", expr]   -> return ("-e option", expr) _              -> error "Needs filename or -e option" case parse (junk *> expr 0 <* eof) name prog of       Left err    -> error $ "Parse error " ++ show err Right e    -> do            hSetEncoding stdin latin1 hSetEncoding stdout latin1 hSetBuffering stdout NoBuffering interact $ churchToString. fun (e []). stringToChurch