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
|
# 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
6
load
|
@ -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
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:
|
# 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" "$@"
|
||||||
|
}
|
||||||
|
|
71
src/fold
71
src/fold
|
@ -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
72
src/map
|
@ -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}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
22
test/test
22
test/test
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue