About Functional-Basic

Functional-Basic (FB for short) is a language that only allows numbers and lists. Basic features, such as the if statement are missing in an attempt to simplify the language.

Everything in this language is immutable. input is always assigned to the script input, which can be either a number or a list.

Basic operators

Note that you must support the order of operations for these. (https://en.wikipedia.org/wiki/Order_of_operations#Definition)

• +: Addition - Applies to both numbers and lists.
• -: Subtraction - Only applies numbers.
• *: Multiplication - Only applies numbers.
• /: Division - Only applies numbers.
• ^: Exponentiation - Only applies numbers.

Functions you must implement

• sum: List of numbers -> Number Sum a list of numbers. Sum of [] is 0.
• product: List of numbers -> Number Get the product of a list. Product of [] is 1.
• print: Anything -> [empty list] Print the value to standard out. Returns empty list. print always ends in a newline.

Output format of the print function

The output should look like how it would be coded literally into the program, with the minor change that one space is required after a comma in lists. The values infinity and negative infinity are Infinity and -Infinity respectively. Not a number is represented by NaN.

Syntax

The syntax for FB is very simplistic. Below is a description of each major section of the syntax.

Useful terms

identifier : a string of only letters


Variable declaration

Though I call them variables, they are really immutable. The only place where a space is required in the syntax is between the [name] and let. names will never contain numbers, just upper and lower case ASCII letters. For simplicity you can assume that identifiers will never be used twice, even in for loops. Also names will not overlap with built-ins (let, sum, for, ...). Syntax:

let [identifier] = [some expression][newline]


Some examples:

let sumOfLst=sum [1,2]
let prod    = product [2,2]


Numbers

Numbers in FB conform to the IEEE 754/854 standard, with implementations providing a minimum of 32-bit precision. NaN, Infinity and -Infinity will not occur in the program source, but may be a result of a calculation.

Lists

Lists have a very limited set of capabilities. You can add lists together with +, and you can map over them with for. No indexed array access is supported here. Lists can have nested list inside them, but if it does it won't have any numbers as direct sub-children (i.e. lists don't mix types). List have only 2 ways to be created, the literal syntax and by mapping over a list with a for loop.

Syntax is just like most list types in other languages.

Examples:

let b = []  <-- not sure what you can do with a empty list...
let c = [5, 6]
let d = [5, []]             <-- invalid
let e = [[5, 2, 6], [6]]    <-- valid
let f = [5] + 5             <-- invalid
let g = [5] + [5]           <-- valid
let h = [[6, 2], []] + []   <-- valid
let i = [[6, 2], []] + [5]  <-- invalid


For loops

For loops in FB behave much like map in other languages in that it returns a list with the function applied to each element of the list. For simplicity you will never have nested for loops. Identifiers from outer scopes may be used in the expression. The expression will always be on the same line.

Syntax:

for ([identifier] in [list, may
be an identifier pointing to a list]) [expression]


Examples:

for(x in lst) x+1
let nList = for (bestNameEver in [2, 5, 6]) bestNameEver^2
let lstOfLsts = for (i in b) [b, b+1]
for(x in [1, 2, 3])print x


Functions

Really only 3 functions exist in FB, sum, product, and print. Refer to the list above for definition of how they should work. All functions have an arity of 1. Function application consists of the name of the function, a space and an expression as the argument. Functions will take the very next thing after them as their argument, even if it is another function. If the arg is another function it will force the evaluation of that function to receive it's arguments. Example:

print sum [5]
prints argument is sum.
print (sum) [5]
sum grabs the list since that is the next thing and evaluates it.
print (5)


Syntax:

[function name][minimum one space][expression as the argument]


Examples:

print [5, 1]
sum   [6, 7]
print 1+2    <-- This is invalid, because print grabs the 1
and returns [], and []+2 is invalid
print (1+2)  <-- This is valid


Other syntax features

Parenthesis are supported.

Example:

print ((1+2)*5)


Handling errors

You can assume that all programs you will receive are syntactically correct and will not violate any rules placed on numbers and lists. The only thing that results in a error case is division by zero (x/0). If you encounter a division by zero you simply halt execution of your program and print Division by zero! to either stdout or stderr.

Examples

Code and output. (> denotes code):

>print sum [1, 2, 3]
6

>print for (x in [1, 2, 3]) x+2
[3, 4, 5]

>let aFloat = 4.2
>let aInt = 5
>let aList = [aFloat, aInt]
>print product aList
21

>let x = for (y in [2.3, 5.6]) y/5*6
>print product x
18.5472

>let superSecretNumber = 0
>print superSecretNumber
0

Input: [2, 3, 4]
>for (i in input) print i*2
4
6
8

>let answerToLife = 6*9
>print answerToLife
54

>print print sum [5, 2]
7
[]

>let a = [1, 2, 3]
>let b = for (x in a) [x, x+1]
>print b
[[1, 2], [2, 3], [3, 4]]

>print print []
[]
[]

>print for (i in [1, 2, 3]) print i
1
2
3
[[], [], []]

• Um... 42=6*9? Mind=blown! – TanMath Jan 16 '16 at 2:35
• – J Atkin Jan 16 '16 at 3:03
• So do we need to have 6*9 set to 42? – TanMath Jan 16 '16 at 3:05
• @TanMath The answer to life is now 54! – J Atkin Jan 16 '16 at 3:08
• And 42 / 2 = 21.... i think everyone still remembers that 9 + 10 joke – Star OS Jan 16 '16 at 8:16

Python 2.7, 979

I'm sure I could golf it further, but I don't see the point yet as I'm the only answer for the moment - I'm a bit lazy

Here is the code of my interpreter :

import sys,re
V={}
S=lambda m:re.sub(' +',';',m).split(';')
def P(t):print t;return []
def E(t):
if len(t)==1:return t[0]
y=E(t[1:])
return{'print':'P('+y+')','sum':'sum('+y+')','product':'reduce(lambda x,y:x*y'+y+',1)'}[t[0]]
def e(t):
y=t[0]
if y=='let':v=V[t[1]]=e(t[3:]);return v
if y=='print':v=e(t[1:]);return P(v)
if y=='sum':return sum(e(t[1:]))
if y=='product':return reduce(lambda x,y:x*y,e(t[1:]),1)
if y=='for':c=S(R(t[1][1:-1].replace('/',' ')));return eval('map(lambda %s:%s,%s)' % (c[0],E(t[2:]),str(e(c[2:]))))
if y[0]=='[':v=V['input']=eval(re.sub('([a-zA-Z]+)',"V['\\1']",y));return v
if re.match('[0-9]+',y):v=V['input']=eval(y);return v
return V[y]
def R(s, u='[',e=']',r=''):
m,b='',1
for c in s:
if b:
m+=c
if c==u:b=0
else:
m+=r if c==' 'else c
if c==e:b=1
return m
def i(s):
try:e(S(R(R(s.replace('^','**'),'(',')','/'))))
except ZeroDivisionError:print 'Division by zero!';sys.exit(1)
while 1:print '>',;i(raw_input())


You can play with it here

• This tip may be of use to you. Nice job! I wonder if someone will go sub 600. – J Atkin Jan 19 '16 at 14:19