kunigami
kunigami

Reputation: 3086

Chained calls in Ocaml

I'm trying to express a set of chained calls in a more imperative fashion. For example, image we have a function that takes a list and an element and it appends the element to the end of the list:

let insert l e =
  l @ [e]

I want to insert a few elements, one at a time. A functional way to do this could be:

let myList = insert (insert (insert [] 3) 4) 5)

I've recently learned about the |> operator, which helps with expressiveness. Together with currying, it can lead to a clean chaining. The problem is that we need to bind the second argument first. This requires defining a function to reverse the arguments (which is actually what |> does :P):

let myList =
  let insertIn l e = insert e l in
    [] |>
    insertIn 3 |>
    insertIn 4 |>
    insertIn 5
;;

This is almost what I want, except the need to defined insertIn. Is there a cleaner way to do this?

I was hoping there was a special operator like $ which could represent the return value of the previous function:

let myList =
  [] |>
  insert $ 3 |>
  insert $ 4 |>
  insert $ 5
;;

Upvotes: 2

Views: 1638

Answers (2)

V. Michel
V. Michel

Reputation: 1619

let (|>) x f y = f x y;;

let myList =
 (((
    []         |>
    insert ) 3 |>
    insert ) 4 |>
    insert ) 5
  ;;

 val myList : int list = [3; 4; 5]

Upvotes: 2

Tarmil
Tarmil

Reputation: 11362

One possible approach, which is common in Haskell, is using flip:

let flip f x y = f y x

let myList =
  [] |>
  flip insert 3 |>
  flip insert 4 |>
  flip insert 5

But really, if the insert function is one that you wrote yourself, then you should rather consider changing its definition in either one of these ways:

  • Flip its arguments so that the list comes last, aka "standard library style":

    let insert e l =
      l @ [e]
    
    let myList =
      [] |>
      insert 3 |>
      insert 4 |>
      insert 5
    
  • Use a named argument, which allows you to pass it out of order, aka "Core style":

    let insert l ~elt:e =
      l @ [e]
    
    let myList =
      [] |>
      insert ~elt:3 |>
      insert ~elt:4 |>
      insert ~elt:5
    

(Also, a side note: your insert is very inefficient because you're copying the whole l every time; lists are designed to be constructed by prepending elements to the front with ::, not appending to the back.)

Upvotes: 7

Related Questions