Browse Source

Rewrite everything, even adding lambda versions

master
Arash Rouhani 10 years ago
parent
commit
0225c1b4c5
  1. 41
      README.md
  2. 6
      load
  3. 17
      src/each
  4. 57
      src/filter
  5. 71
      src/fold
  6. 72
      src/map
  7. 22
      test/test

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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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…
Cancel
Save