2018-03-10 18:47:25 -05:00
|
|
|
# Introduction
|
|
|
|
|
|
|
|
[Introduction to fun.sh library](http://ssledz.github.io/presentations/bash-fun.html#/)
|
|
|
|
|
|
|
|
# Quick start
|
|
|
|
|
|
|
|
```bash
|
|
|
|
#!/bin/bash
|
|
|
|
. <(test -e fun.sh || curl -Ls https://raw.githubusercontent.com/ssledz/bash-fun/master/src/fun.sh > fun.sh; cat fun.sh)
|
|
|
|
|
|
|
|
seq 1 4 | sum
|
|
|
|
```
|
|
|
|
|
|
|
|
# Functions overview
|
2018-03-10 18:53:54 -05:00
|
|
|
|||||||
|
|
|
|
|------|------|------|------|------|------|
|
2019-09-30 18:02:34 -04:00
|
|
|
|**append**|**buff**|**call**|**catch**|**curry**|**div**|
|
|
|
|
|**drop**|**dropw**|**factorial**|**filter**|**foldl**|**foldr**|
|
|
|
|
|**isint**|**isempty**|**isfile**|**isnonzerofile**|**isreadable**|**iswritable**|
|
|
|
|
|**isdir**|**join**|**lambda**|**last**|**lhead**|**list**|
|
|
|
|
|**ltail**|**lzip**|**map**|**maybe**|**maybemap**|**maybevalue**|
|
|
|
|
|**mod**|**mul**|**not**|**ntup**|**ntupl**|**ntupr**|
|
|
|
|
|**ntupx**|**peek**|**plus**|**prepend**|**product**|**ret**|
|
|
|
|
|**res**|**revers**|**revers_str**|**scanl**|**splitc**|**strip**|
|
|
|
|
|**stripl**|**stripr**|**sub**|**sum**|**take**|**try**|
|
|
|
|
|**tup**|**tupl**|**tupr**|**tupx**|**unlist**|**λ**|
|
|
|
|
|**with_trampoline**|
|
2018-03-10 18:47:25 -05:00
|
|
|
|
|
|
|
## *list/unlist*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ list 1 2 3
|
|
|
|
1
|
|
|
|
2
|
|
|
|
3
|
|
|
|
|
|
|
|
$ list 1 2 3 4 5 | unlist
|
|
|
|
1 2 3 4 5
|
|
|
|
```
|
|
|
|
|
2019-09-30 18:02:34 -04:00
|
|
|
## *take/drop/ltail/lhead/last*
|
2018-03-10 18:47:25 -05:00
|
|
|
|
|
|
|
```bash
|
|
|
|
$ list 1 2 3 4 | drop 2
|
|
|
|
3
|
|
|
|
4
|
|
|
|
|
2019-09-30 18:02:34 -04:00
|
|
|
$ list 1 2 3 4 5 | lhead
|
2018-03-10 18:47:25 -05:00
|
|
|
1
|
|
|
|
|
2019-09-30 18:02:34 -04:00
|
|
|
$ list 1 2 3 4 | ltail
|
2018-03-10 18:47:25 -05:00
|
|
|
2
|
|
|
|
3
|
|
|
|
4
|
|
|
|
|
|
|
|
$ list 1 2 3 4 5 | last
|
|
|
|
5
|
|
|
|
|
|
|
|
$ list 1 2 3 4 5 | take 2
|
|
|
|
1
|
|
|
|
2
|
|
|
|
```
|
|
|
|
|
|
|
|
## *join*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ list 1 2 3 4 5 | join ,
|
|
|
|
1,2,3,4,5
|
|
|
|
|
|
|
|
$ list 1 2 3 4 5 | join , [ ]
|
|
|
|
[1,2,3,4,5]
|
|
|
|
```
|
|
|
|
|
|
|
|
## *map*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ seq 1 5 | map λ a . 'echo $((a + 5))'
|
|
|
|
6
|
|
|
|
7
|
|
|
|
8
|
|
|
|
9
|
|
|
|
10
|
|
|
|
|
|
|
|
$ list a b s d e | map λ a . 'echo $a$(echo $a | tr a-z A-Z)'
|
|
|
|
aA
|
|
|
|
bB
|
|
|
|
sS
|
|
|
|
dD
|
|
|
|
eE
|
2019-08-30 20:03:35 -04:00
|
|
|
|
|
|
|
$ list 1 2 3 | map echo
|
|
|
|
1
|
|
|
|
2
|
|
|
|
3
|
|
|
|
|
|
|
|
$ list 1 2 3 | map 'echo $ is a number'
|
|
|
|
1 is a number
|
|
|
|
2 is a number
|
|
|
|
3 is a number
|
|
|
|
|
|
|
|
$ list 1 2 3 4 | map 'echo \($,$\) is a point'
|
|
|
|
(1,1) is a point
|
|
|
|
(2,2) is a point
|
|
|
|
(3,3) is a point
|
|
|
|
(4,4) is a point
|
2018-03-10 18:47:25 -05:00
|
|
|
```
|
|
|
|
|
|
|
|
## *flat map*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ seq 2 3 | map λ a . 'seq 1 $a' | join , [ ]
|
|
|
|
[1,2,1,2,3]
|
|
|
|
|
|
|
|
$ list a b c | map λ a . 'echo $a; echo $a | tr a-z A-z' | join , [ ]
|
|
|
|
[a,A,b,B,c,C]
|
|
|
|
```
|
|
|
|
|
|
|
|
## *filter*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ seq 1 10 | filter λ a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false'
|
|
|
|
2
|
|
|
|
4
|
|
|
|
6
|
|
|
|
8
|
|
|
|
10
|
|
|
|
```
|
|
|
|
|
|
|
|
## *foldl/foldr*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ list a b c d | foldl λ acc el . 'echo -n $acc-$el'
|
|
|
|
a-b-c-d
|
|
|
|
|
|
|
|
$ list '' a b c d | foldr λ acc el .\
|
|
|
|
'if [[ ! -z $acc ]]; then echo -n $acc-$el; else echo -n $el; fi'
|
|
|
|
d-c-b-a
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ seq 1 4 | foldl λ acc el . 'echo $(($acc + $el))'
|
|
|
|
10
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ seq 1 4 | foldl λ acc el . 'echo $(mul $(($acc + 1)) $el)'
|
|
|
|
64 # 1 + (1 + 1) * 2 + (4 + 1) * 3 + (15 + 1) * 4 = 64
|
|
|
|
|
|
|
|
$ seq 1 4 | foldr λ acc el . 'echo $(mul $(($acc + 1)) $el)'
|
|
|
|
56 # 1 + (1 + 1) * 4 + (8 + 1) * 3 + (27 + 1) * 2 = 56
|
|
|
|
```
|
|
|
|
|
|
|
|
## *tup/tupx/tupl/tupr*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ tup a 1
|
|
|
|
(a,1)
|
|
|
|
|
|
|
|
$ tup 'foo bar' 1 'one' 2
|
|
|
|
(foo bar,1,one,2)
|
|
|
|
|
|
|
|
$ tup , 1 3
|
|
|
|
(u002c,1,3)
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ tupl $(tup a 1)
|
|
|
|
a
|
|
|
|
|
|
|
|
$ tupr $(tup a 1)
|
|
|
|
1
|
|
|
|
|
|
|
|
$ tup , 1 3 | tupl
|
|
|
|
,
|
|
|
|
|
|
|
|
$ tup 'foo bar' 1 'one' 2 | tupl
|
|
|
|
foo bar
|
|
|
|
|
|
|
|
$ tup 'foo bar' 1 'one' 2 | tupr
|
|
|
|
2
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ tup 'foo bar' 1 'one' 2 | tupx 2
|
|
|
|
1
|
|
|
|
|
|
|
|
$ tup 'foo bar' 1 'one' 2 | tupx 1,3
|
|
|
|
foo bar
|
|
|
|
one
|
|
|
|
|
|
|
|
$ tup 'foo bar' 1 'one' 2 | tupx 2-4
|
|
|
|
1
|
|
|
|
one
|
|
|
|
2
|
|
|
|
```
|
|
|
|
|
2019-09-30 18:02:34 -04:00
|
|
|
## *ntup/ntupx/ntupl/ntupr*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ ntup a 1 b 2 c 3
|
|
|
|
(YQo=,MQo=,Ygo=,Mgo=,Ywo=,Mwo=)
|
|
|
|
|
|
|
|
$ echo '(YQo=,MQo=,Ygo=,Mgo=,Ywo=,Mwo=)' | ntupx 3
|
|
|
|
b
|
|
|
|
|
|
|
|
$ ntup 'foo bar' 1 one 1
|
|
|
|
(Zm9vIGJhcgo=,MQo=,b25lCg==,MQo=)
|
|
|
|
|
|
|
|
$ echo '(Zm9vIGJhcgo=,MQo=,b25lCg==,MQo=)' | ntupx 1
|
|
|
|
foo bar
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ ntupl $(ntup 'foo bar' 1 one 2)
|
|
|
|
foo bar
|
|
|
|
|
|
|
|
$ ntupr $(ntup 'foo bar' 1 one 2)
|
|
|
|
2
|
|
|
|
```
|
|
|
|
|
2018-03-10 18:47:25 -05:00
|
|
|
## *buff*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ seq 1 10 | buff λ a b . 'echo $(($a + $b))'
|
|
|
|
3
|
|
|
|
7
|
|
|
|
11
|
|
|
|
15
|
|
|
|
19
|
|
|
|
|
|
|
|
$ seq 1 10 | buff λ a b c d e . 'echo $(($a + $b + $c + $d + $e))'
|
|
|
|
15
|
|
|
|
40
|
|
|
|
```
|
|
|
|
|
2019-09-30 18:02:34 -04:00
|
|
|
## *lzip*
|
2018-03-10 18:47:25 -05:00
|
|
|
|
|
|
|
```bash
|
2019-09-30 18:02:34 -04:00
|
|
|
$ list a b c d e f | lzip $(seq 1 10)
|
2018-03-10 18:47:25 -05:00
|
|
|
(a,1)
|
|
|
|
(b,2)
|
|
|
|
(c,3)
|
|
|
|
(d,4)
|
|
|
|
(e,5)
|
|
|
|
(f,6)
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
2019-09-30 18:02:34 -04:00
|
|
|
$ list a b c d e f | lzip $(seq 1 10) | last | tupr
|
2018-03-10 18:47:25 -05:00
|
|
|
6
|
|
|
|
```
|
|
|
|
|
|
|
|
## *curry*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
add2() {
|
|
|
|
echo $(($1 + $2))
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ curry inc add2 1
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ inc 2
|
|
|
|
3
|
|
|
|
|
|
|
|
$ seq 1 3 | map λ a . 'inc $a'
|
|
|
|
2
|
|
|
|
3
|
|
|
|
4
|
|
|
|
```
|
|
|
|
|
2019-09-30 18:02:34 -04:00
|
|
|
## *peek*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ list 1 2 3 \
|
|
|
|
| peek lambda a . echo 'dbg a : $a' \
|
|
|
|
| map lambda a . 'mul $a 2' \
|
|
|
|
| peek lambda a . echo 'dbg b : $a' \
|
|
|
|
| sum
|
|
|
|
|
|
|
|
dbg a : 1
|
|
|
|
dbg a : 2
|
|
|
|
dbg a : 3
|
|
|
|
dbg b : 2
|
|
|
|
dbg b : 4
|
|
|
|
dbg b : 6
|
|
|
|
12
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ a=$(seq 1 4 | peek lambda a . echo 'dbg: $a' | sum)
|
|
|
|
|
|
|
|
dbg: 1
|
|
|
|
dbg: 2
|
|
|
|
dbg: 3
|
|
|
|
dbg: 4
|
|
|
|
|
|
|
|
$ echo $a
|
|
|
|
|
|
|
|
10
|
|
|
|
```
|
|
|
|
|
|
|
|
## *maybe/maybemap/maybevalue*
|
|
|
|
|
|
|
|
TODO
|
|
|
|
|
|
|
|
## *not/isint/isempty*
|
|
|
|
|
|
|
|
TODO
|
|
|
|
|
|
|
|
## *isfile/isnonzerofile/isreadable/iswritable/isdir*
|
|
|
|
|
|
|
|
TODO
|
|
|
|
|
2018-03-10 18:47:25 -05:00
|
|
|
## *try/catch*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ echo 'expr 2 / 0' | try λ _ . 'echo 0'
|
|
|
|
0
|
|
|
|
|
|
|
|
$ echo 'expr 2 / 0' | try λ status . 'echo $status'
|
|
|
|
2
|
|
|
|
|
|
|
|
$ echo 'expr 2 / 2' | try λ _ . 'echo 0'
|
|
|
|
1
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
try λ _ . 'echo some errors during pull; exit 1' < <(echo git pull)
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ echo 'expr 2 / 0' \
|
|
|
|
| LANG=en catch λ cmd status val . 'echo cmd=$cmd,status=$status,val=$val'
|
|
|
|
cmd=expr 2 / 0,status=2,val=(expr:,division,by,zero)
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ echo 'expr 2 / 2' | catch λ _ _ val . 'tupl $val'
|
|
|
|
1
|
|
|
|
```
|
|
|
|
|
|
|
|
## *scanl*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ seq 1 5 | scanl lambda acc el . 'echo $(($acc + $el))'
|
|
|
|
1
|
|
|
|
3
|
|
|
|
6
|
|
|
|
10
|
|
|
|
15
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | last
|
|
|
|
15
|
|
|
|
```
|
|
|
|
|
|
|
|
## *with_trampoline/res/call*
|
|
|
|
|
|
|
|
```bash
|
|
|
|
factorial() {
|
|
|
|
fact_iter() {
|
|
|
|
local product=$1
|
|
|
|
local counter=$2
|
|
|
|
local max_count=$3
|
|
|
|
if [[ $counter -gt $max_count ]]; then
|
|
|
|
res $product
|
|
|
|
else
|
|
|
|
call fact_iter $(echo $counter\*$product | bc) $(($counter + 1)) $max_count
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
with_trampoline fact_iter 1 1 $1
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ time factorial 30 | fold -w 70
|
|
|
|
265252859812191058636308480000000
|
|
|
|
|
|
|
|
real 0m1.854s
|
|
|
|
user 0m0.072s
|
|
|
|
sys 0m0.368s
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
time factorial 60 | fold -w 70
|
|
|
|
8320987112741390144276341183223364380754172606361245952449277696409600
|
|
|
|
000000000000
|
|
|
|
|
|
|
|
real 0m3.635s
|
|
|
|
user 0m0.148s
|
|
|
|
sys 0m0.692s
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ time factorial 90 | fold -w 70
|
|
|
|
1485715964481761497309522733620825737885569961284688766942216863704985
|
|
|
|
393094065876545992131370884059645617234469978112000000000000000000000
|
|
|
|
|
|
|
|
real 0m4.371s
|
|
|
|
user 0m0.108s
|
|
|
|
sys 0m0.436s
|
|
|
|
```
|
|
|
|
|
|
|
|
# Examples
|
|
|
|
|
|
|
|
```bash
|
|
|
|
processNames() {
|
|
|
|
|
|
|
|
uppercase() {
|
|
|
|
local str=$1
|
|
|
|
echo $(tr 'a-z' 'A-Z' <<< ${str:0:1})${str:1}
|
|
|
|
}
|
|
|
|
|
|
|
|
list $@ \
|
|
|
|
| filter λ name . '[[ ${#name} -gt 1 ]] && ret true || ret false' \
|
|
|
|
| map λ name . 'uppercase $name' \
|
|
|
|
| foldl λ acc el . 'echo $acc,$el'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
processNames adam monika s slawek d daniel Bartek j k
|
|
|
|
```
|
|
|
|
|
|
|
|
```bash
|
|
|
|
Adam,Monika,Slawek,Daniel,Bartek
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
# Resources
|
2018-03-10 19:05:59 -05:00
|
|
|
* [Inspiration](https://quasimal.com/posts/2012-05-21-funsh.html)
|
|
|
|
* [Functional Programming in Bash](https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7)
|