Interpret Functional-Basic

7

1

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
[[], [], []]

J Atkin

Posted 2016-01-15T23:42:47.890

Reputation: 4 846

Um... 42=6*9? Mind=blown! – TanMath – 2016-01-16T02:35:15.593

So do we need to have 6*9 set to 42? – TanMath – 2016-01-16T03:05:28.067

@TanMath The answer to life is now 54! – J Atkin – 2016-01-16T03:08:30.277

And 42 / 2 = 21.... i think everyone still remembers that 9 + 10 joke – Star OS – 2016-01-16T08:16:33.663

So function application binds tighter than exponentiation? PS Patience is a virtue

– Peter Taylor – 2016-01-16T09:00:30.897

Yes it does, I am trying to simplify the parsing and evaluating of FB as much as possible. The way I am thinking of parsing it with my own code this would help greatly. – J Atkin – 2016-01-16T14:29:06.860

Just a quick example. sum list ^ 2. My imaginary parser sees the ^, grabs list and 2. It has a fit since list isn't a number. If function application is first sum list is evaluated first, and no problems all around. This could be fixed by adding parenthesis around (sum list) or by the parser noticing the improper type and looking for a function, but both of those are longer than the current way. – J Atkin – 2016-01-16T15:04:17.153

I suppose variables cannot be named let, sum, etc., right? – coredump – 2016-01-18T19:06:05.343

Correct, I should add that to the spec... – J Atkin – 2016-01-18T19:24:07.363

Ewww, infix notation! – cat – 2016-01-19T03:30:39.840

I thought this was using prefix notation for functions, and infix for math operators (common)... – J Atkin – 2016-01-19T03:34:50.937

Answers

4

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

dieter

Posted 2016-01-15T23:42:47.890

Reputation: 2 010

This tip may be of use to you. Nice job! I wonder if someone will go sub 600. – J Atkin – 2016-01-19T14:19:09.340