How to print current item from `|>` and keep piping it forward?


#1

Map.to_alist subtrees
|> List.rev
|> List.map ~f:(fun subtree -> subtree_to_table options subtrees subtree group_table)
|> List.concat
|> fun ls -> (ls, group_table)

My question is, how do I output the current List size with List.concat without affecting the incoming input? Look forward to your advice. Thank you!
Perhaps my description is not clear, please allow me to use error code roughly to show my intention.

Map.to_alist subtrees
|> List.rev
|> List.map ~f:(fun subtree -> subtree_to_table options subtrees subtree group_table)
|> let a_list = List.concat in printf “%d\n” (List.length a_list); List.concat
|> fun ls -> (ls, group_table)


#2

I just want to intercept the intermediate data, but it doesn’t affect subsequent incoming input.


#3

Something like this…?

Map.to_alist subtrees
|> List.rev
|> List.map ~f:(fun subtree -> subtree_to_table options subtrees subtree group_table)
|> (fun xs -> printf “%d\n” (List.length xs); xs)
|> List.map (fun ls -> (ls, group_table))


#4

Perfect, it works! You’re my God. Thank you!


#5

You can use a generic function called tee:

let tee f x = f x; x

This lets you do basically anything in the middle of a pipeline and pass the original value forward afterwards. E.g.,

foo
|> List.map ...
|> tee (fun l -> printf "%d\n" (List.length l))
|> List.concat
|> ...

The name comes from the Unix utility tee which does pretty much the same thing in the shell.


#6

You’re a genius. I admire your good idea. Thank you.


#7

For even better integration with the pipeline, I often define the
tee function as let (|-) x f = f x; x, leading to:

foo
|> List.map ...
|- (fun l -> printf "%d\n" (List.length l))
|> List.concat
|> ...

#8

Good idea, thank you!


#9

There is CCFun.tap in OCaml-containers lib which can also help:

https://c-cube.github.io/ocaml-containers/2.0/containers/CCFun/index.html#val-tap