Implement functional programming paradigms

21

6

Your company is just getting started on a project, and for the first time you decided to go use a functional programming code-style. However your boss is really diffident and doesn't want to use built-in functions, and requires you to implement yourself the main functions. In particular you need to write the functions: Map, Nest, Apply, Range, Fold and Table in a language on your choice. The boss is a really busy man, and he wants to have the programs as short as possible, so he doesn't waste time reading. He also would like not for you to use loops, therefore you will have a 10% reduction on the byte count for not using loops.

The detailed requirements of the functions are below:

Map

The Map function takes two parameters: f and list where f is a function and list is a list of values. It should return the f applied to each element of list. Therefore it will work as such:

Map(f,{a,b,c})

returns

{ f(a), f(b), f(c) }

and

Map(f, {{a,b},{b,c}})

returns

{ f({a,b}), f({b,c})}

Nest

The Nest function takes three parameters as well: f, arg, times where f is a function, arg is its starting argument, and times is how many times the function is applied. It should return an expression with f applied times times to arg. Therefore it will work as such:

Nest(f, x, 3)

returns

f(f(f(x)))

and

Nest(f, {a,b}, 3)

returns

f(f(f({a,b})))

Apply

The Apply function takes two parameters: f and args where f is a function and args a list. It should apply f to the args. Therefore:

Apply(f, {a,b,c})

returns

f(a,b,c)

Range

The Range function takes one integerr and outputs the integers up to that number. Therefore:

Range(5)

returns

{ 1, 2, 3, 4, 5}

Fold

The Fold function takes three parameters f, arg, others where f is a function, arg is simple parameter, and others a list. It will work as such:

Fold(f, x, {a, b, c, d})

returns

f(f(f(f(x,a),b),c),d)

Table

The table functions should take a function f, and a parameter called iterator in the form: {iMin, iMax} where iMin and iMax are integers. You should apply f over the range specified. Therefore:

Table(f, {0, 5})

returns

{f(0), f(1), f(2), f(3), f(4), f(5)}

I've used the definition of these functions from the Mathematica functional programming page, so head there if you need any more guidance. Note that you will not need to implement all the version of the functions shown in that page, but only those written in this post.

Standard Loopholes are disallowed as usual.

In case your language does not allow functions to be passed as arguments, you need to implement this capability, and add it into your answer. However the byte-count of this operation will not be added to the total.

This is code golf so the shortest code wins. Good luck!!!

WizardOfMenlo

Posted 2015-09-24T13:16:45.723

Reputation: 843

This is awesome! +1 However, I don't really get how Table works here. Is your example supposed to be Table(f, {x, 0, 5})? I also don't get the purpose of x at all, since it just applies the function to the range. – kirbyfan64sos – 2015-09-24T14:05:42.837

@kirbyfan64sos Thank you! Yes that was a typo, I left x in as a reference to mathematica, which uses it as symbolic feauture, however I think I can get it out – WizardOfMenlo – 2015-09-24T14:08:11.717

One more question: how do we name the functions? Do we have to give them the exact same names? Single-letter? – kirbyfan64sos – 2015-09-24T14:15:02.797

@kirbyfan64sos Since it is code-golf, I'll allow single letter names, however in your answer put a heading over each function so that we know which one it is. Also do not use colliding letters. – WizardOfMenlo – 2015-09-24T14:18:02.657

Could you be more specific about what counts as a loop? – xnor – 2015-09-24T17:59:03.817

@xnor no you can't, what I'm really interested in is the implementation of the features. As what counts for loop I think for and while loops, and the use of gotos to emulate them – WizardOfMenlo – 2015-09-24T18:01:31.653

By the way, that's the wrong fold for languages that offer infinite lists. Those languages really want f(a, f(b, f(c, f(d, x)))). – dfeuer – 2015-09-24T18:10:16.260

Is the 10% bonus per function, i.e. a total of 60% for the whole code if no function uses loops? – nimi – 2015-09-24T19:22:14.470

@nimi originally I was going for that approach, but I think the 10% if no loops are used in all code is more adapt – WizardOfMenlo – 2015-09-24T19:29:38.760

You use Map(f, {{a,b},{b,c}}) resulting in { f(a, b), f(b, c) } - is that f taking a single argument, the list {a, b}? Or is it f taking in two distinct arguments a and b? – Dannnno – 2015-09-24T21:00:45.167

@Dannnno it is f taking a single argument, a list, I wrote it wrongly, well spotted – WizardOfMenlo – 2015-09-24T21:03:09.763

I assume the same for the other ones? – Dannnno – 2015-09-24T21:03:37.313

@Dannnno where exactly? As a reference I used this page, https://reference.wolfram.com/language/guide/FunctionalProgramming.html, so it should reflect those

– WizardOfMenlo – 2015-09-24T21:04:40.807

Range is for positive integers only? What happens with 0 or with a negative number? – Dannnno – 2015-09-24T21:05:00.637

For example, Nest. I would expect Nest(f, {a,b}, 3) to give me f(f(f({a, b}))) but you have f(f(f(a, b))) – Dannnno – 2015-09-24T21:05:36.180

@Dannnno Range is for positive integers indeed, Nest follows the same rule as well, so you're right – WizardOfMenlo – 2015-09-24T21:07:34.540

May I use one of the functions to implement another? – edc65 – 2015-09-24T22:11:00.247

@edc65 yes of course, just define it before its usage :) – WizardOfMenlo – 2015-09-24T22:11:29.927

My language has built-in functionality for all these, so may I just assign your names to cover-functions? – Adám – 2015-09-25T15:44:43.630

@NBZ the challenge states that built-ins are not allowed – WizardOfMenlo – 2015-09-25T15:47:15.957

What means "returns an expression"? Does this mean we should return something which needs to be evaluated later, or can we evaluate it immediately and return the result of that evaluation? – Paŭlo Ebermann – 2015-11-22T16:50:34.100

@PaŭloEbermann, it can be evaluated immediately, see other answers as guidlines, I think that the Haskell one is quite indicative. – WizardOfMenlo – 2015-11-22T16:58:16.873

@dfeuer I think you got it wrong – your version would need to iterate the whole list before starting to evaluate f, while the version in the question evaluates f during each step. – Paŭlo Ebermann – 2015-11-22T17:27:54.787

If some of the functions use loops and the others not, do these others still get the 10% reduction? – Paŭlo Ebermann – 2015-11-22T19:01:07.713

@PaŭloEbermann no, to be elegible for the bonus there needs to be no looping in general – WizardOfMenlo – 2015-11-22T19:05:42.600

@Paŭlo Ebermann, I was referring to lazy lists. A lazy function passed to a right fold can be productive on an infinite list. It's possible to implement left folds in terms of right ones but not (in the infinite case) the other way around. – dfeuer – 2015-11-23T03:14:12.383

@dfeuer so you would have not just a lazy list, but also a lazy fold (i.e. f(a, f(b, ...)) would only calculate the second parameter of the first when (an if) actually needed by f's implementation? I guess that works. I was thinking about a non-lazy fold (maybe with side effects), i.e. an endless loop for an infinite list, which wouldn't work with right-folding. – Paŭlo Ebermann – 2015-11-23T13:21:18.543

@PaŭloEbermann, take a look at how it's done in Haskell. In the latest library version, the left fold is actually defined in terms of the right: foldl f b0 xs = foldr (\x r b -> r (f b x)) id xs b0 – dfeuer – 2015-11-23T15:07:30.090

Answers

9

Haskell, many previous byte counts 127 * 0.9 = 114.3 bytes

f#(a:b)=f a:f#b;f#x=x
(f&x)0=x;(f&x)i=f$f&x$i-1
i=id
r x=i%(1,x)
(g?x)(a:b)=g(g?x$b)a;(g?x)y=x
f%(a,b)|a>b=[]|1<2=f a:f%(a+1,b)

No loops, just recursion.

# is map: (*2) # [1,2,3] -> [2,4,6]

& is nest: ((*2) & 3) 4 -> 48

i is apply: i (*2) 7 -> 14

r is range: r 4 -> [1,2,3,4]

? is fold: ((+) ? 0) [1,2,3,4] -> 10

% is table: (*2) % (2,4) -> [4,6,8]

As requested an ungolfed version with comments. Note, & and ? are ternary infix operators, which require additional parentheses when called or pattern matched.

f # (a:b) = f a : f#b        -- map on a list (a->head, b->tail) is f a in front of mapping f to b
f # x     = x                -- map on the empty list is the empty list
                             -- (non empty lists are caught in the line before) 

(f & x) 0 = x                -- nesting zero times is x
(f & x) i = f $ f&x $ i-1    -- nesting i times is f (nesting one time less)

i=id                         -- apply in Haskell is just the identity function 

r x = i % (1,x)              -- defined via the "table" of the identity function from 1 to x

(g ? x) (a:b) = g (g?x$b) a  -- folding g into a list (a->head, b->tail) is g applied to (folding g into b) and a
(g ? x) y     = x             -- folding the empty list is x
                             --  again, y must be the empty list, else it would have been handled by the previous line

f % (a,b)                    
  |a>b       = []                -- if iMin is greater than iMax, the table is empty
  |otherwise = f a : f%(a+1,b)   --  otherwise f a in front of the table with iMin increased by one

Thanks to @dfeuer and @Zgarb for some useful hints

nimi

Posted 2015-09-24T13:16:45.723

Reputation: 34 639

I'm new to haskell, it looks quite good, however could you please add an explanation to what you are doing? – WizardOfMenlo – 2015-09-24T17:46:32.537

1@WizardOfMenlo: added some comments – nimi – 2015-09-24T18:00:54.630

Just realized how elegant Haskell is, real good! – WizardOfMenlo – 2015-09-24T18:10:20.807

1Ignoring infinite lists and efficiency, m#q=reverse$f((:).m)[]q. This is the same length as yours, but much harder to read. – dfeuer – 2015-09-24T18:21:32.963

You can shorten ! by making it a name instead of an operator: i f=f. – dfeuer – 2015-09-24T18:36:21.943

Now that you have i, you can use it in the definition of r for another byte. – dfeuer – 2015-09-24T18:46:23.413

n and f can both be defined as infix, but you need parentheses: (f&x)1=f x;(f&x)i=f$f&x$i-1 for n, and similarly for f. Also, swapping the cases of # and doing f#x=x for the empty list saves 2 bytes. – Zgarb – 2015-09-24T18:50:16.460

To save 3 more bytes: swap the definitions of ? and do (g?x)y=x for empty lists, and do (f&x)0=x for the base case of &. – Zgarb – 2015-09-24T19:57:06.223

@Zgarb: thanks again – nimi – 2015-09-24T21:13:25.020

@nimi I've removen the accepted answer just to draw a bit more attention to the question, I will put it back again soon :) (Unless someone beats you) – WizardOfMenlo – 2015-11-22T20:07:33.840

5

Python 2, 305.1 bytes (-10% 376 369 366 349 339 bytes)

exec'e=eval;q=len;m=@,l:e("["+"f(l.pop()),"*q(l)+"][::-1]");n=@,x,l:e("f("*l+"*x"+")"*l);r=@:e("r(f-1)+"*(f>1)+"[f]");a=@,a:e("f(a["+`r(q(a))`[1:-1]$",","-1],a[")+"-1])");f=@,x,l:e("f("*q(l)+"x,["+`r(q(l))`[1:-1]$",","-1]),l[")+"-1])");t=@,n,x:e("[f("+`r(x)[n-1:]`$",","),f(")[1:-1]+")]")'.replace("@","lambda f").replace("$",".replace(")

When expanded, equivalent to:

e=eval;q=len
m=lambda f,l:e("["+"f(l.pop()),"*q(l)+"][::-1]")
n=lambda f,x,l:e("f("*l+"*x"+")"*l)
r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
a=lambda f,a:e("f(a["+`r(q(a))`[1:-1].replace(",","-1],a[")+"-1])")
f=lambda f,x,l:e("f("*q(l)+"x,["+`r(q(l))`[1:-1].replace(",","-1]),l[")+"-1])")
t=lambda f,n,x:e("[f("+`r(x)[n-1:]`.replace(",","),f(")[1:-1]+")]")

No loops!

Well, it does a lot of evaling and if your boss can't stand loops, then they'll HATE eval. But, they're going to have to put up with it

A way to do range in a lambda is appreciated so I don't have to do any functions (Shudder.).

Explanations:

  • m=lambda f,l:eval("["+"f(l.pop()),"*len(l)+"][::-1]")
    • Create a string that pops elements from the list, wrap it into a list, reverse it and finally eval it!
  • n=lambda f,x,l:eval("f("*l+"*x"+")"*l)
    • Manually create the string with the nesting, and eval it!
  • r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
    • Create a string that when evaled, either returns [0] or uses recursion to get the previous results and adds the current index to the list. Evals it.
  • a=lambda f,a:eval("f(a["+r(len(a))[1:-1].replace(",","-1],a[")+"-1])")
    • Uses the range function to get the indexes 1-len(list). Replaces the commas in the list stringified with a way to get the correct index of the list a. Evals it!
  • f=lambda f,x,l:eval("f("*len(l)+"x,["+r(len(l))[1:-1].replace(",","-1]),l[")+"-1])")
    • Same as apply except replaces the commas with closing brackets, commas and starting the list index.
  • t=lambda f,n,x:eval("[f("+r(x)[n-1:].replace(",","),f(")[1:-1]+")]")
    • Same as apply and fold except replaces with ending the function and calling the new one. Evals it!

Map, nest, range, apply, fold, table.

Thanks @Zgarb for a lambda for range!

Blue

Posted 2015-09-24T13:16:45.723

Reputation: 26 661

My boss will have my head on his desk :) Could you add a brief explanation as well please? – WizardOfMenlo – 2015-09-24T19:08:11.643

How about r=lambda i:[]if i<1 else r(i-1)+[i]? No loops, only recursion. – Zgarb – 2015-09-24T19:23:40.393

1Sure, I'll take that for now but the boss needs more eval to show them how for loops aren't so bad :) – Blue – 2015-09-24T19:25:01.407

Ha! Another version using e=eval: r=lambda i:e("r(i-1)+"*(i>1)+"[i]") – Zgarb – 2015-09-24T19:31:52.357

can you change it from the 60% bonus to a 10% please? I revised the question specification, so to make it fairer – WizardOfMenlo – 2015-09-24T20:53:56.060

Might want to make an alias to replace: R=str.replace. Then instead of s.replace(x,y) you can do R(s,x,y). – Cyoce – 2016-04-02T03:41:29.537

5

Javascript ES6, 197 * 0.9 = 177.3 bytes

M=(f,l)=>F((a,b)=>[...a,f(b)],[],l)
N=(f,x,n)=>f(--n?N(f,x,n):x)
A=(f,l)=>f(...l)
R=n=>n--?[...R(n),n+1]:[]
F=(f,x,l,n=l.length)=>n--?f(F(f,x,l,n),l[n]):x
T=(f,i)=>([n,x]=i,M(q=>f(q+n-1),R(x-n+1)))

Map (M=(f,l)=>F((a,b)=>[...a,f(b)],[],l)):

Uses Fold to concat the results of f applied to every member of l onto an empty list. Using built-in functions reduces the this to M=(f,l)=>l.map(f) (didn't use it because it seems cheap...?).

Nest (N=(f,x,n)=>f(--n?N(f,x,n):x)):

Apply f recursively until n is decremented to 0.

Apply (A=(f,l)=>f(...l)):

Uses the spread (...) operator to apply l onto f.

Range (R=n=>n--?[...R(n),n+1]:[]):

Concat n to recursive call of Range until n is decremented to 0.

Fold (F=(f,x,l,n=l.length)=>n--?f(F(f,x,l,n),l[n]):x):

Applies the recursive call of Fold and the n'th element of l to f until n is decremented to 0. Using built-in functions reduces this to F=(f,x,l)=>l.reduce(f,x) (again, seemed cheap...).

Table (T=(f,i)=>([n,x]=i,M(q=>f(q+n-1),R(x-n+1)))):

First initializes n and x to iMin and iMax using destructuring ([n,x]=i), then uses Range to construct the table of values from iMin to iMax. f is then applied over the table using Map and the result is returned.

Dendrobium

Posted 2015-09-24T13:16:45.723

Reputation: 2 412

Wanna know my philosophy? "If it's cheap, buy it." It doesn't say in the specs that you can't use builtins (yet), so use them! – Mama Fun Roll – 2015-11-11T01:04:04.167

4

Julia, 181 bytes

No bonus for me; I used loops liberally. Sorry boss, but loops in Julia are efficient!

M(f,x)=[f(i...)for i=x]
N(f,x,n)=(for i=1:n x=f(x...)end;x)
A(f,x)=f(x...)
R(n)=(i=0;x={};while i<n push!(x,i+=1)end;x)
F(f,x,a)=(for b=a x=f(x,b)end;x)
T(f,i)=[f(j)for j=i[1]:i[2]]

Adding the ellipses after an argument to a function breaks an array, tuple, or what have you into regular function arguments. Otherwise the function will think you're trying to pass an array (or tuple, etc.). It has no effect for single arguments.

Function names:

  • Map: M
  • Nest: N
  • Apply: A
  • Range: R
  • Fold: F
  • Table: T

Alex A.

Posted 2015-09-24T13:16:45.723

Reputation: 23 761

4

Python 3, 218 bytes

The unreadable version:

exec("P!:[f(_)for _ in x];Y!,z:Y(f,f(x),z-1)if z else x;T!:f(*x);H!=0:(H(f-1)if~-f else[])+[f];O!,z:O(f,f(x,z[0]),z[1:])if z else x;N!:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]".replace("!","=lambda f,x"))

The (more) readable version:

P=lambda f,x:[f(_)for _ in x]
Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
T=lambda f,x:f(*x)
H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]

Going though it one lambda at a time:

Map function P

P=lambda f,x:[f(_)for _ in x]
Just a simple iterator. Not much to say here.

Nest function Y

Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
Recursing until z hits zero, applying f every time. The if clause at the end feels clunky; perhaps there is a better way to end the recursion.

Apply function T

T=lambda f,x:f(*x)
Python has a nice expansion operator to do all of the heavy lifting for me.

Range function H

H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
This one was harder than I was expecting. Ended up taking a recursive approach. Again, the if-else construction takes up a lot of bytes, and I feel it can be improved. Why does it have a dummy x=0, you ask? It's so that when I compress it with the exec, I can replace =lambda f,x instead of just =lambda f.

Fold function O

O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
Pretty happy with this one. Just lops off the first element of the array every time it recurses, until there's nothing left.

Table function N

N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]
This one is horrible and I'm sure there's room for improvement. Tried to use the range and map functions previously defined for a map(f,range(x,y)) sort of construction, but without much success. Ended up doing a terrible recursive approach which shares some similarity to the range function.

All the lambdas are wrapped up in an exec with a replace to shorten the byte count significantly.

Tryth

Posted 2015-09-24T13:16:45.723

Reputation: 750

I was about to comment that [f(_)for _ in x] could be shortened to map(f,x), but then I remembered what the challenge was – Cyoce – 2016-09-08T16:26:28.273

4

tinylisp, 325 * 0.9 = 292.5

The language is newer than the question, but it's not going to win anyway.

(d @(q(a a)))(d Q(q((l)(i l(c(@(q q)(h l))(Q(t l)))l))))(d A(q((f a)(v(c(q f)(Q a))))))(d M(q((f l)(i l(c(A f(@(h l)))(M f(t l)))l))))(d N(q((f a x)(i x(A f(@(N f a(s x 1))))a))))(d ,(q((m a b)(i(l b a)m(,(c b m)a(s b 1))))))(d R(q((a)(,()1 a))))(d T(q((f r)(M f(A ,(c()r))))))(d F(q((f a l)(i l(F f(A f(@ a(h l)))(t l))a))))

Defines the functions A (apply), M (map), N (nest), R (range), T (table), and F (fold), along with a couple helper functions. T expects a list of two integers for its second argument.

Tinylisp doesn't even have any loop constructs; everything is accomplished using recursion. Several of these functions are not tail-recursive, so if you call them on large lists they will probably blow the call stack. They could all be implemented with tail recursion... but it would take more bytes, and this is code golf.

Here's an expanded version with whitespace and real words for names, which should be pretty readable if you're familiar with Lisp. (I've aliased most of the tinylisp builtins except for q (quote) and i (if).)

(d define d)
(define cons c)
(define car h)
(define cdr t)
(define subtract s)
(define less l)
(define eval v)

(define lambda
  (q (()
      (arglist expr)
      (list arglist expr))))

(define list (lambda args args))

(define quote-all
  (lambda (lyst)
    (i lyst
       (cons
         (list (q q) (car lyst))
         (quote-all (cdr lyst)))
       lyst)))

(define Apply
  (lambda (func arglist)
    (eval (cons (q func) (quote-all arglist)))))

(define Map
  (lambda (func lyst)
    (i lyst
       (cons
         (Apply func (list (car lyst)))
         (Map func (cdr lyst)))
       lyst)))

(define Nest
  (lambda (func arg times)
    (i times
       (Apply func
              (list (Nest func arg (subtract times 1))))
       arg)))

(define range*
  (lambda (accumulator a b)
    (i (less b a)
       accumulator
       (range* (cons b accumulator) a (subtract b 1)))))

(define Range
  (lambda (x)
    (range* 1 x)))

(define Table
  (lambda (func iterator)
    (Map func
         (Apply range* (cons () iterator)))))

(define Fold
  (lambda (func arg lyst)
    (i lyst
       (Fold func
             (Apply func (list arg (car lyst)))
             (cdr lyst))
       arg)))

Further explanation available upon request.

Sample output

Uses the REPL environment from my reference implementation. I used q (quote) for the unary function and s (subtract) as the binary function for these examples, as well as the function @ (defined in this code) which returns a list of its arguments.

tl> [line of definitions goes here]
@
Q
A
M
N
,
R
T
F
tl> (A s (@ 10 7))
3
tl> (M q (@ 1 2 3 4))
((q 1) (q 2) (q 3) (q 4))
tl> (N q 123 4)
(q (q (q (q 123))))
tl> (R 5)
(1 2 3 4 5)
tl> (T q (@ 3 7))
((q 3) (q 4) (q 5) (q 6) (q 7))
tl> (F s 10 (@ 4 3 2))
1

DLosc

Posted 2015-09-24T13:16:45.723

Reputation: 21 213

2

Python 2.x: 450.6 bytes (493 bytes before 10% discount)

Golfed answer:

y=len
z=lambda a,b:a.append(b)
_=lambda a:a if a is not None else[]
def M(a,b,c=None):
 c=_(c);d=y(b)
 if d:z(c,A(a,b[0]))
 return M(a,b[1:],c)if d else c
def N(a,b,c):d=A(a,b);return N(a,d,c-1)if c>1 else d
A=lambda a,b:a(*b)if type(b)is list else a(b)
def R(a,b=None):b=_(b);b.insert(0,a);return b if a<=1 else R(a-1,b)
def F(a,b,c):d=a(b,c[0]);return F(a,d,c[1:])if y(c)>1 else d
def T(a,b,c=None,d=None):
 if c is None:c=b[0];d=[]
 z(d,a(c));return T(a,b,c+1,d)if c<b[1]else d

This question was fun. I decided to write my functions without using the Python equivalents (though that may have been a valid loophole) and to write the functions as though Python supports tail recursion. To make this work, I used a lot of optional parameters that allow the required calls to still work.

Below I have ungolfed listings for each function.

Apply:

A = lambda function, arguments: function(*arguments) if type(arguments) is list else function(arguments)

Map:

def M(function, arguments, result=None):
    result = result if result is not None else []
    length = len(arguments)
    if length != 0:
        result.append(A(function, arguments[0]))
    return M(function, arguments[1:], result) if length != 0 else result

Nest:

def N(function, arguments, times):
    result = A(function, arguments)
    return N(function, result, times - 1) if times > 1 else result

Note that this function requires that the passed function be able to represent multiple arguments variably. Another approach would have been to enforce that the function always received a single list, but that would have required that the passed functions be able to interpret argument lists. There were assumptions either way, so I chose the one that fit the rest of the system better.

Range:

def R(ceiling, result=None):
    result = result if result is not None else []
    result.insert(0, ceiling)
    return result if ceiling <= 1 else R(ceiling - 1, result)

Fold:

def F(function, initial, rest):
    result = function(initial, rest[0])
    return F(function, result, rest[1:] if len(rest) > 1 else result

Table:

def T(function, iterator, current=None, result=None):
    if current is None:
        current = iterator[0]
        result = []
    result.append(function(current))
    return T(function, iterator, current + 1, result) if current < iterator[1] else result

Here is sample output using the following helper functions:

square = lambda x: x * x
def add(*args):
    addTwo = lambda a, b: a + b
    if len(args) == 1 and type(args[0]) is list:
        return F(addTwo, 0, args[0])
    else:
        return F(addTwo, 0, args)

>>> M(square, R(10))
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> M(add, [R(i) for i in R(10)])
[1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
>>> T(square, [0, 10])
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> N(square, 2, 4)
65536
>>> N(lambda *args: F(lambda a, b: a * b, 1, args) if len(args) > 1 else str(args[0]) + 'a', R(5), 10)
'120aaaaaaaaa'

sadakatsu

Posted 2015-09-24T13:16:45.723

Reputation: 619

Wow, looks really good! – WizardOfMenlo – 2015-09-24T17:58:07.990

That seems like a skewed sense of aesthetics ; ) I always find it amusing to see golfed Python since the first Python book I read talked about how Python enforces readability. – sadakatsu – 2015-09-24T18:03:45.057

I do indeed have a skewed sense of aesthetics :) – WizardOfMenlo – 2015-09-24T18:07:04.763

I am confused by other people's scores. I took 10% of the score of each of the required functions which did not use a loop (which was all of them), but other people took 10% of the whole score for each function that did not use a loop (which can be up to 60% off). Which is the correct approach? – sadakatsu – 2015-09-24T20:48:46.087

Yours is the correct way to go, I had an unrealistic expectation and so initially I had in mind the 60% approach, but now I think the 10% will be more stimulating and the righter between the two – WizardOfMenlo – 2015-09-24T20:52:46.083

2

Ceylon, 370 * 0.9 = 333 364 * 0.9 = 327.4

Most of those functions are already available in Ceylon's language package (though sometimes with a bit different signature), but we are defining them here like requested in the question.

alias I=>Integer;R[]m<A,R>(R(A)g,A[]l)=>f((R[]x,A y)=>x.append([g(y)]),[],l);A n<A>(A(A)g,A a,I t)=>f((A x,I y)=>g(x),a,r(t));R y<A,R>(Callable<R,A>g,A v)given A satisfies Anything[]=>g(*v);I[]r(I i)=>t((j)=>j,[1,i]);A f<A,O>(A(A,O)g,A a,O[]o)=>if(nonempty o)then f(g,g(a,o[0]),o.rest)else a;R[]t<R>(R(I)g,[I,I]i)=>i[1]<i[0]then[]else[g(i[0]),*t(g,[i[0]+1,i[1]])];

Actually only two of the functions (t and f) are actually using recursion (over lists and integers, respectively), the other ones are based on these. (Apply is a bit of an outlier, it doesn't really relate to the others.)

I interpret "List" as Ceylon's Sequential type, which is an immutable ordered (possibly empty) sequence of elements. [R*] stands for Sequential<R> – for some reason we can also write it R[], which is one byte shorter.

A function type is Callable<R, A>, where A is a tuple type for the arguments, like [X, Y, Z] (i.e. some subtype of Anything[]). As a shortcut we can write R(X,Y,Z) instead of Callable<R,[X,Y,Z]>.

I aliased Integer as I to save some bytes.

Here is a formatted (and slightly commented) version:

// implement functional paradigms
//
// Question: http://codegolf.stackexchange.com/q/58588/2338
// My Answer: http://codegolf.stackexchange.com/a/64515/2338

alias I => Integer;

// map – based on fold.
R[] m<A, R>(R(A) g, A[] l) =>
        f((R[]x,A y) => x.append([g(y)]), [], l);

// nest – based on fold + range, throwing away the second
//        argument in a proxy function.
A n<A>(A(A) g, A a, I t) =>
        f((A x, I y) => g(x), a, r(t));

// apply – this looks quite heavy due to type safety.
//         This uses the "spread operator" *.
R y<A, R>(Callable<R,A> g, A v)
        given A satisfies Anything[] =>
        g(*v);

// range – based on table (using the identity function)
I[] r(I i) =>
        t((j) => j, [1, i]);

// fold – a plain list recursion.
A f<A, O>(A(A, O) g, A a, O[] o) =>
        if (nonempty o) then f(g, g(a, o[0]), o.rest) else a;

// table – an integer recursion.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        i[1] < i[0] then [] else [g(i[0]), *t(g, [i[0] + 1, i[1]])];

Using "loops"

Table and Map can be implemented shorter using loops (actually, an sequence comprehension):

// map – using a sequence comprehension:
R[] m<A, R>(R(A) g, A[] l) =>
        [for(a in l) g(a)];

// table – map with an integer range.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        m(g, i[0]..i[1]);

Though I'm not sure if the use of the .. operator for the integer range counts as using a built-in function. If this is allowed, the resulting code is this here, length 312:

alias I=>Integer;R[]m<A,R>(R(A)g,A[]l)=>[for(a in l)g(a)];A n<A>(A(A)g,A a,I t)=>f((A x,I y)=>g(x),a,r(t));R y<A,R>(Callable<R,A>g,A v)given A satisfies Anything[]=>g(*v);I[]r(I i)=>t((j)=>j,[1,i]);A f<A,O>(A(A,O)g,A a,O[]o)=>if(nonempty o)then f(g,g(a,o[0]),o.rest)else a;R[]t<R>(R(I)g,[I,I]i)=>m(g,i[0]..i[1]);

(It could be made even shorter by defining r(I i) => 1..i, resulting in score 301. Though that looks even more like cheating.)

If .. is not allowed, we'll have to implement it again. We can use these implementations for r and t (with the m above):

// range – based two-limit range 
I[] r(I i) =>
        q(1, i);

// two-limit range implemented recursively
I[] q(I i, I j) =>
        j < i then [] else [i, *q(i + 1, j)];


// table – map with an integer range.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        m(g, q(i[0], i[1]));

This results in 348 bytes, better than the completely recursive version, but not after applying the bonus.

Paŭlo Ebermann

Posted 2015-09-24T13:16:45.723

Reputation: 1 010

0

Groovy (146 Bytes) (146*90%=131.4)

P.S. I don't know what you're considering as a 'loop' in this context, I only applied the bonus after I was told to in the comments by OP and will remove if 2-3 additional users say these collection functions and iterators are loops and that I don't deserve the bonus. Also, if you want to call me out on my use of 1..it, please do so and I will rework it / update my bytecount.

m={f,l->l.collect{f(it)}}            // Map
n={f,x,n->n.times{x=f(x)};x}         // Nest
a={f,l->f(l)}                        // Apply
r={1..it}                            // Range (Is this cheating?)
f={f,x,l->l.each{x=f(x,it)};x}       // Fold
t={f,l->(l[0]..l[1]).collect{f(it)}} // Table

Example Input/Output

f1={2*it}
f2={a,b,c,d,e->a*b*c*d*e}
f3={a,b->a*b}
l=[1,2,3,4,5]
l2=[1,9]
y=5
x=1
println m(f1,l)
println n(f1,x,y)
println a(f2,l)
println r(y)
println f(f3,x,l)
println t(f1,l2)

Output

MAP:   [2, 4, 6, 8, 10]
NEST:  32
APPLY: 120
RANGE: [1, 2, 3, 4, 5]
FOLD:  120
TABLE: [2, 4, 6, 8, 10, 12, 14, 16, 18]

Try it yourself: https://groovyconsole.appspot.com/edit/5203951758606336

Magic Octopus Urn

Posted 2015-09-24T13:16:45.723

Reputation: 19 422

This technically does not use loops, so remember the bonus! Else, great answer! – WizardOfMenlo – 2016-09-08T18:53:50.380

Technically no loops?! Really?! .each{} .times{} .collect{} are iterators. – Magic Octopus Urn – 2016-09-08T18:55:41.190