Created
August 1, 2011 15:18
-
-
Save autotelicum/1118326 to your computer and use it in GitHub Desktop.
Partial application with free vars
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/node /Users/eh/bin/coffee | |
# Adjust according to install and chmod +x script | |
# Compatibility with both node.js and browsers | |
show = if exports? then console.log else alert | |
# Step-by-step derivation of a short version of | |
# partial function application with free vars. | |
# Inspired by http://blog.mirotin.net/tag/coffeescript | |
# 15 - Fix indentation of i++ | |
_ = {} | |
partial = () -> | |
[func, args...] = arguments | |
wrapper = () -> | |
i = 0 | |
j = 0 | |
res_args = [] | |
while i < args.length | |
if args[i] == _ | |
res_args.push arguments[j] | |
j++ | |
else | |
res_args.push args[i] | |
i++ | |
return func.apply null, res_args | |
# 12 - Use splats and remove redundant words | |
_ = {} | |
partial = (func, args...) -> | |
(moreargs...) -> | |
i = j = 0 | |
res_args = [] | |
while i < args.length | |
if args[i] == _ | |
res_args.push moreargs[j++] | |
else | |
res_args.push args[i] | |
i++ | |
func.apply null, res_args | |
# 10 - Use while as an expression | |
_ = {} | |
partial = (func, args...) -> | |
(moreargs...) -> | |
i = j = 0 | |
func.apply null, | |
while i++ < args.length | |
if args[i-1] == _ | |
moreargs[j++] | |
else | |
args[i-1] | |
# 5 - Use for loop and splat in call | |
_ = {} | |
partial = (func, a...) -> (b...) -> | |
i = 0 | |
func (for arg in a | |
if arg == _ then b[i++] else arg)... | |
# 5 - Eliminate low level counter | |
_ = {} | |
partial = (func, a...) -> (b...) -> | |
b.reverse() | |
func (for arg in a | |
if arg == _ then b.pop() else arg)... | |
# 4 - Use undefined instead of empty object | |
_ = undefined | |
partial = (func, a...) -> (b...) -> | |
b.reverse() | |
func (for arg in a then arg ?= b.pop())... | |
# Make it 140 char twitter compatible with semicolons | |
#CoffeeScript partial with free vars | |
#_ = undefined; partial = (f, a...) -> (b...) -> b.reverse(); f (for arg in a then arg ?= b.pop())... | |
# Export module definitions | |
(exports ? this)._ = _ | |
(exports ? this).partial = partial | |
# Command line adhoc test | |
if process.argv[1] == __filename | |
name = (require 'path').basename __filename, '.coffee' | |
f = (x, y, z) -> x + 2*y + 5*z | |
g = partial f, _, 1, _ | |
show "#{name} => #{g 3, 5}" # partialFreeVars => 30 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/node /Users/eh/bin/coffee | |
# Compatibility with both node.js and browsers | |
show = if exports? then console.log else alert | |
{_, partial} = require './partialFreeVars' | |
# Command line adhoc test | |
if process.argv[1] == __filename | |
name = (require 'path').basename __filename, '.coffee' | |
f = (x, y, z) -> x + 2*y + 5*z | |
g = partial f, _, 1, _ | |
show "#{name} => #{g 3, 5}" # partialFreeVars => 30 | |
# Modified from alexkg example | |
fold = (f, z, xs) -> | |
z = f(z, x) for x in xs | |
z | |
max = partial fold, Math.max, -Infinity, _ | |
show max [-10..10] | |
# Without free vars | |
partial = (f, a...) -> (b...) -> f a..., b... | |
min = partial fold, Math.min, Infinity | |
show min [-10..10] # => -10 |
From A Tour of Scala: Currying
object CurryTest extends Application {
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
if (xs.isEmpty) xs
else if (p(xs.head)) xs.head :: filter(xs.tail, p)
else filter(xs.tail, p)
def modN(n: Int)(x: Int) = ((x % n) == 0)
val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
println(filter(nums, modN(2)))
println(filter(nums, modN(3)))
}
// => List(2,4,6,8)
// => List(3,6)
In CoffeeScript becomes:
do curryTest = ->
filter = (xs, p) -> x for x in xs when p x
partial = (f, a...) -> (b...) -> f a..., b...
modN = (n, x) -> x % n is 0
nums = [1..8]
console.log filter nums, partial modN, 2
console.log filter nums, partial modN, 3
# => [ 2, 4, 6, 8 ]
# => [ 3, 6 ]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Found this related implementation in JavaScript, that predates mirotin's:
http://javascriptweblog.wordpress.com/2010/05/17/partial-currys-flashy-cousin/