This is the pipe mill[1] pattern. As you say, you can use it to mimic function composition from a functional paradigm. It can make for some elegant solutions to dealing with streams of data.
The issue is that pipe mills are very slow.
$ mill() { while read -r line; do echo $line; done }
$ export FIVE_MEGS=$(( 5 * 1024 ** 2 ))
$ time yes | mill | pv -S -s "$FIVE_MEGS" > /dev/null
5.00MiB 0:00:23 [ 221KiB/s] [============>] 100%
real 0m23.084s
user 0m14.121s
sys 0m26.780s
$ time yes | pv -S -s "$FIVE_MEGS" > /dev/null
5.00MiB 0:00:00 [6.55GiB/s] [============>] 100%
real 0m0.005s
user 0m0.000s
sys 0m0.006s
Even Python loops are faster.
$ export PYLOOP="from sys import stdin
for line in stdin:
print(line)"
$ time yes | python3 -c "$PYLOOP" | pv -S -s "$FIVE_MEGS" > /dev/null
5.00MiB 0:00:00 [67.1MiB/s] [============>] 100%
real 0m0.082s
user 0m0.071s
sys 0m0.019s
The issue is that pipe mills are very slow.
Even Python loops are faster. [1] https://en.wikipedia.org/wiki/Pipeline_(Unix)#Pipemill