Rewrite everything, even adding lambda versions
This commit is contained in:
parent
b2d0210212
commit
0225c1b4c5
7 changed files with 200 additions and 86 deletions
41
README.md
41
README.md
|
@ -1,16 +1,41 @@
|
|||
# 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`
|
||||
|
||||
mkdir ~/.zsh
|
||||
git clone https://github.com/yogsototh/zsh_functional.git ~/.zsh/functional
|
||||
|
||||
and add
|
||||
To install, clone this repo to `~/.zsh/functional` and add
|
||||
|
||||
. ~/.zsh/functional/load
|
||||
|
||||
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
6
load
|
@ -1,7 +1,5 @@
|
|||
# Load functions
|
||||
func_reps=( ~/.zsh/functional/src )
|
||||
for rep in $func_reps; do
|
||||
fpath=($rep $fpath)
|
||||
autoload -U $rep/*(:t)
|
||||
for file in ~/.zsh/functional/src/* ; do
|
||||
. $file
|
||||
done
|
||||
|
||||
|
|
17
src/each
Normal file
17
src/each
Normal 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" "$@"
|
||||
}
|
||||
|
57
src/filter
57
src/filter
|
@ -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" "$@"
|
||||
}
|
||||
|
|
71
src/fold
71
src/fold
|
@ -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
72
src/map
|
@ -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}"
|
||||
}
|
||||
|
||||
|
|
22
test/test
22
test/test
|
@ -32,10 +32,20 @@ fi
|
|||
echo "Starting tests of zsh higher order functions"
|
||||
|
||||
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 )) }
|
||||
TEST "filter can remove odd numbers" "filter divisible_by_two {0..4}" "0 2 4"
|
||||
|
||||
divisible_by_two () { (( $1%2 == 0 )) }
|
||||
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"
|
||||
|
|
Loading…
Reference in a new issue