Rewrite everything, even adding lambda versions

This commit is contained in:
Arash Rouhani 2012-07-08 23:27:52 +02:00
parent b2d0210212
commit 0225c1b4c5
7 changed files with 200 additions and 86 deletions

View file

@ -1,16 +1,41 @@
# ZSH higher order functions # ZSH higher order functions
You can look at [this article] to have more informations. You can look at [yogsototh's blogpost] for the idea of higher order functions
in zsh.
To install just clone it to `~/.zsh/functional` To install, clone this repo to `~/.zsh/functional` and add
mkdir ~/.zsh
git clone https://github.com/yogsototh/zsh_functional.git ~/.zsh/functional
and add
. ~/.zsh/functional/load . ~/.zsh/functional/load
to your `.zshrc` to your `.zshrc`
[this article]: http://yannesposito.com/Scratch/en/blog/Higher-order-function-in-zsh/ ## Usage and documentation
Please refer to the tests so far until I've written simple proper docs for each
function. The function `map` and family will print out documentation for you
when calling them with no arguments.
Each of the method families, `map`, `each`, `filter` and `fold` are having a
"normal version" accompanied with lambda function version and a arithmetic
lambda version.
### Lambda functions
Use the versions ending with `l`, like `mapl`, `eachl`, `foldl`.
### Arithmetic lambda functions
Similarly, use the functions ending with `a`.
## Contributing
Good idea! Just add a test and implement the new functionality and send away
your pull request! :)
## Creds
Yann Esposito for the *HoF* idea and big thanks to [Sterling's blogpost] for
discovering and starting implementing the anonymous function features.
[yogsototh's blogpost]: http://yannesposito.com/Scratch/en/blog/Higher-order-function-in-zsh/
[Sterling's blogpost]: http://nicholassterling.wordpress.com/2012/03/30/a-zsh-map-function/

6
load
View file

@ -1,7 +1,5 @@
# Load functions # Load functions
func_reps=( ~/.zsh/functional/src ) for file in ~/.zsh/functional/src/* ; do
for rep in $func_reps; do . $file
fpath=($rep $fpath)
autoload -U $rep/*(:t)
done done

17
src/each Normal file
View file

@ -0,0 +1,17 @@
eachl() {
typeset f="$1"; shift
typeset x
typeset result=0
for x; each_ "$x" "$f" || result=$?
return $result
}
each_() {
eval "$2"
}
each() {
typeset f="$1 \"\$1\""; shift
eachl "$f" "$@"
}

View file

@ -1,29 +1,38 @@
#!/usr/bin/env zsh
# usage: # usage:
# #
# $ baz() { print $1 | grep baz } # $ baz() { print $1 | grep baz }
# $ filter baz titi bazaar biz # $ filter baz titi bazaar biz
# bazaar # bazaar
# filter() { filter() {
(($#<1)) && { (($#<1)) && {
{ {
print -- "usage: filter func list" print -- "usage: filter func list"
print print
print -- "example:" print -- "example:"
print -- ' > baz(){print "$*" | grep baz}' print -- ' > baz(){print "$*" | grep baz}'
print -- ' > filter baz titi bazaar biz' print -- ' > filter baz titi bazaar biz'
print -- ' bazaar' print -- ' bazaar'
} >&2 } >&2
return 1 return 1
} }
local predicate=$1 typeset f="$1 \"\$1\""; shift
local result filterl "$f" "$@"
typeset -a result }
shift
for elem in $@; do filterl() {
if eval $predicate $elem >/dev/null; then typeset f="$1"; shift
result=( $result $elem ) typeset x
fi for x; filter_ "$x" "$f"
done return 0
print $result }
# } filter_() {
eval "$2" && print -- "$1"
}
### filtera ArithRelation Arg ... # is shorthand for
### filter '(( ArithRelation ))' Arg ...
filtera() {
typeset f="(( $1 ))"; shift
filterl "$f" "$@"
}

View file

@ -1,27 +1,44 @@
#!/usr/bin/env zsh fold () {
if (($#<2)) { if (($#<2)) {
{ {
print -- 'usage: fold function list' print -- 'usage: fold function list'
print print
print -- 'example:' print -- 'example:'
print -- ' > bar() { print $(($1 + $2)) }' print -- ' > bar() { print $(($1 + $2)) }'
print -- ' > fold bar 0 1 2 3 4 5' print -- ' > fold bar 0 1 2 3 4 5'
print -- ' 15' print -- ' 15'
} >&2 } >&2
return 1 return 1
} } else {
if (($#<3)) { typeset f="\$($1 \$acc \$1)"; shift
print -- $2 foldl "$f" "$@"
return 0 }
} else { }
local acc
local right foldl () {
local func_name=$1 if (($#<2)) {
local init_value=$2 {
local first_value=$3 print -- 'Warning, l is not for left! Its for lambda style expression!'
shift 3 print -- 'Though this is left fold still :)'
right=$( fold $func_name $init_value $@ ) } >&2
acc=$( eval "$func_name $first_value $right" ) return 1
print -- $acc } else {
return 0 local body=$1
} local acc=$2
shift 2
for x; acc=$(fold_ $x $acc $body)
print -- $acc
return 0
}
}
folda () {
typeset f="\$[ $1 ]"; shift
foldl "$f" "$@"
}
fold_ () {
local acc=$2
local body=$3
print "${(e)body}"
}

72
src/map
View file

@ -1,19 +1,57 @@
#!/usr/bin/env zsh
map() { map() {
(($#<1)) && { (($#<1)) && {
print -- "usage: map funcname [list]" print -- "usage: map funcname [list]"
print print
print -- 'example:' print -- 'example:'
print -- ' > foo(){print "x: $1"}' print -- ' > foo(){print "x: $1"}'
print -- ' > map foo a b c d' print -- ' > map foo a b c d'
print -- ' x: a' print -- ' x: a'
print -- ' x: b' print -- ' x: b'
print -- ' x: c' print -- ' x: c'
print -- ' x: d' print -- ' x: d'
return 1 return 1
} }
local func_name=$1 local func_name=$1
shift shift
for elem in $@; print -- $(eval $func_name $elem) for elem in $@; print -- $(eval $func_name $elem)
} }
mapl () {
(($#<1)) && {
print -- "usage: mapl lambda-function [list]"
print
print -- 'example:'
print -- " > mapl 'echo \"x: \$1\"' a b c d"
print -- ' x: a'
print -- ' x: b'
print -- ' x: c'
print -- ' x: d'
return 1
}
typeset f="$1"; shift
typeset x
typeset result=0
for x; map_ "$x" "$f" || result=$?
return $result
}
mapa () {
(($#<1)) && {
print -- "usage: mapa lambda-arithmetic [list]"
print -- " (shorthand for mapl '$[ f ]' [list])"
print
print -- 'example:'
print -- " > mapa '\$1+5' {1..3}"
print -- ' 6'
print -- ' 7'
print -- ' 8'
return 1
}
typeset f="\$[ $1 ]"; shift
mapl "$f" "$@"
}
map_ () {
print -- "${(e)2}"
}

View file

@ -32,10 +32,20 @@ fi
echo "Starting tests of zsh higher order functions" echo "Starting tests of zsh higher order functions"
plus_one () { echo $(($1+1)) } plus_one () { echo $(($1+1)) }
TEST "map can (+1) numbers" "map plus_one {0..5}" "1 2 3 4 5 6" divisible_by_two () { (( $1%2 == 0 )) }
divisible_by_two () { (( $(($1%2)) == 0 )) }
TEST "filter can remove odd numbers" "filter divisible_by_two {0..4}" "0 2 4"
addition () { echo $(($1 + $2)) } addition () { echo $(($1 + $2)) }
TEST "fold can sum numbers" "fold addition 0 {1..5}" "15" ignore_acc () { echo $2 }
TEST "map can (+1) numbers " "map plus_one {0..5} " "1 2 3 4 5 6"
TEST "mapl echo append " "mapl '\$1 day' good bad " "good day bad day"
TEST "mapa can (+1) " "mapa '\$1 + 5' {1..3} " "6 7 8"
TEST "filter can remove odd numbers " "filter divisible_by_two {0..4} " "0 2 4"
TEST "filterl can grep out words " "filterl 'echo \$1 | grep a --silent' ab bc ac " "ab ac"
TEST "filtera can remove odd numbers " "filtera '\$1%2 == 0' {0..4} " "0 2 4"
TEST "fold can sum numbers " "fold addition 0 {1..5} " "15"
TEST "fold is not commutative " "fold ignore_acc a b c d " "d"
TEST "foldl palin " "foldl '\$1\$acc\$1' MIDDLE = + = = " "==+=MIDDLE=+=="
TEST "foldl palin2 " "foldl '\$1\$2\$1' MIDDLE = + = = " "==+=MIDDLE=+=="
TEST "folda can sum numbers " "folda '\$1+\$2' 0 {1..5} " "15"
TEST "each can only append " "each 'echo young' boy girl " "young boy young girl"
TEST "eachl can prepend " "eachl 'echo \$1 day' good bad " "good day bad day"