Merge pull request #1 from Tarrasch/master

Clean readme and simplify installation
This commit is contained in:
Yann Esposito 2012-07-09 14:36:56 -07:00
commit 57e3c3c522
7 changed files with 240 additions and 82 deletions

View file

@ -1,20 +1,41 @@
# ZSH higher order functions
You can look at [yogsototh's blogpost] for the idea of higher order functions
in zsh.
You can look at [this article<sup>†</sup>](http://yannesposito.com/Scratch/en/blog/Higher-order-function-in-zsh/) to have more informations.
To install, clone this repo to `~/.zsh/functional` and add
To install just clone it to `~/.zsh/functional`
mkdir ~/.zsh
git clone https://yogsototh@github.com/yogsototh/zsh_functional.git ~/.zsh/functional
and add
# Load functions
func_reps=( ~/.zsh/functional/src )
for rep in $func_reps; do
fpath=($rep $fpath)
autoload -U $rep/*(:t)
done
. ~/.zsh/functional/load
to your `.zshrc`
## 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/

5
load Normal file
View file

@ -0,0 +1,5 @@
# Load functions
for file in ~/.zsh/functional/src/* ; do
. $file
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:
#
# $ baz() { print $1 | grep baz }
# $ filter baz titi bazaar biz
# bazaar
# filter() {
(($#<1)) && {
{
print -- "usage: filter func list"
print
print -- "example:"
print -- ' > baz(){print "$*" | grep baz}'
print -- ' > filter baz titi bazaar biz'
print -- ' bazaar'
} >&2
return 1
}
local predicate=$1
local result
typeset -a result
shift
for elem in $@; do
if eval $predicate $elem >/dev/null; then
result=( $result $elem )
fi
done
print $result
# }
filter() {
(($#<1)) && {
{
print -- "usage: filter func list"
print
print -- "example:"
print -- ' > baz(){print "$*" | grep baz}'
print -- ' > filter baz titi bazaar biz'
print -- ' bazaar'
} >&2
return 1
}
typeset f="$1 \"\$1\""; shift
filterl "$f" "$@"
}
filterl() {
typeset f="$1"; shift
typeset x
for x; filter_ "$x" "$f"
return 0
}
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
if (($#<2)) {
{
print -- 'usage: fold function list'
print
print -- 'example:'
print -- ' > bar() { print $(($1 + $2)) }'
print -- ' > fold bar 0 1 2 3 4 5'
print -- ' 15'
} >&2
return 1
}
if (($#<3)) {
print -- $2
return 0
} else {
local acc
local right
local func_name=$1
local init_value=$2
local first_value=$3
shift 3
right=$( fold $func_name $init_value $@ )
acc=$( eval "$func_name $first_value $right" )
print -- $acc
return 0
}
fold () {
if (($#<2)) {
{
print -- 'usage: fold function list'
print
print -- 'example:'
print -- ' > bar() { print $(($1 + $2)) }'
print -- ' > fold bar 0 1 2 3 4 5'
print -- ' 15'
} >&2
return 1
} else {
typeset f="\$($1 \$acc \$1)"; shift
foldl "$f" "$@"
}
}
foldl () {
if (($#<2)) {
{
print -- 'Warning, l is not for left! Its for lambda style expression!'
print -- 'Though this is left fold still :)'
} >&2
return 1
} else {
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() {
(($#<1)) && {
print -- "usage: map funcname [list]"
print
print -- 'example:'
print -- ' > foo(){print "x: $1"}'
print -- ' > map foo a b c d'
print -- ' x: a'
print -- ' x: b'
print -- ' x: c'
print -- ' x: d'
return 1
}
local func_name=$1
shift
for elem in $@; print -- $(eval $func_name $elem)
(($#<1)) && {
print -- "usage: map funcname [list]"
print
print -- 'example:'
print -- ' > foo(){print "x: $1"}'
print -- ' > map foo a b c d'
print -- ' x: a'
print -- ' x: b'
print -- ' x: c'
print -- ' x: d'
return 1
}
local func_name=$1
shift
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}"
}

51
test/test Executable file
View file

@ -0,0 +1,51 @@
#!/usr/bin/env zsh
. ~/.zsh/functional/load # load the functions
# TEST - run a unit test
#
# $1: Test description
# $2: String to eval
# $3: Expected result
TEST() {
desc=$1
code=$2
expected="$3 "
result=$(eval $code | tr "\n" " ")
if [[ $result == $expected ]]; then;
echo "SUCCESS: Test '$desc' passed"
else
echo "FAIL: Test '$desc' yielded $result, expected $expected"
fi
}
if [[ $debug == 1 ]] ; then;
echo "First test the \"test framework\""
TEST "THIS SHOULD SUCCESS" "echo 4" "4"
TEST "THIS SHOULD FAIL" "echo 3" "4"
echo "ok, now lets test what we should test"
echo "\n\n"
fi
echo "Starting tests of zsh higher order functions"
plus_one () { echo $(($1+1)) }
divisible_by_two () { (( $1%2 == 0 )) }
addition () { echo $(($1 + $2)) }
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"