Quick Composing of Functions Inputs in Higher Order Functions

Can you compose functions in a quick way?

E.g. this doesn’t work,

[0,1,2] |> Enum.map (&is_integer &is_integer &1)

but is there another way?

No problem if not, just seems like there might be.

1 Like

I do not even understand what you exactly want here…

Do you want to achieve something along of haskells (.)?

If so, I do think [0,1,2] |> Enum.map(&(is_integer(is_integer(&1)))) comes closest to what you want. Anyway, in this case you could also write [false, false, false] directly, it is a “constant“ expression…


For the sake of completeness, haskells (.) is roughly as in the following elixir code:

def o(f, g, x), do: f(g(x))
2 Likes

That was throw away roughwork I was just tapping into the terminal, was just trying to achieve understanding…

I noticed a small typo in your example (unsure why the extra parens don’t work) this works though…

[0,1,2] |> Enum.map &(is_integer(is_integer(&1)))

and I see I can take another bunch out too…

[0,1,2] |> Enum.map &( is_integer is_integer &1 )

which is nice and clean, and what I was trying to achieve - thanks!

2 Likes

I get a ‘piping into a fn call without parentheses’ warning which I don’t feel makes a lot of sense here - perhaps worth a bug report(?)

1 Like

Nope, not a bug report. After the first pipe you have to use parenthesises. This has been introduced with elixir 1.1 IIRC and has to do with ambiguities that arise otherwise.

Personally I do think that omitting parens like in ruby was a bad design choice and always use them when I have functions that I use as functions.

Thats exactly the cause why there was the extra opening paren in my answer above, I just miscounted and forgot to close it. I will edit my post and correct it.

3 Likes

Aha, you are totally correct (dumb mistake)

[0,1,2] |> ( Enum.map &(is_integer is_integer &1 ) )

works like a charm.

Thanks again.

1 Like

Thats exactly the way NOT to do…

Correct way to write this is [0, 1, 2] |> Enum.map(&(is_integer is_integer &1)), and still I’d prefer to use parens around is_integer/1s arguments also: [0, 1, 2] |> Enum.map(&(is_integer(is_integer(&1))))

I do strongly suggest you a read of the community styleguide.

The samples you give here look a lot more like you are trying to write Haskell, Idris or Agda, but Elixir has a different syntax and you should obey it.

2 Likes

OK, I will hold my hands up - I am lazy when it comes to typing : )

[not in all senses of the word though ; )]

Just an observation - stylistically

[0, 1, 2] |> Enum.map(&(is_integer is_integer &1))

seems to be stuck halfway between

Enum.map [0, 1, 2], &(is_integer is_integer &1) 

and

[0, 1, 2] |> Enum.map(&(&1 |> is_integer |> is_integer))

… in other words, there seems to be a lack of commitment to “Use the pipeline operator (|>) to chain functions together”. :wink:

(took inspiration from Support function composition operators · Issue #756 · elixir-lang/elixir)

1 Like

style fascist ; )

Can some one explain me what is the point of chaining two is_integer functions? :slight_smile:
You always get false I suppose …

I was just being lazy - trying to get the syntax right in my head - could be any two composeable functions

Personally, I’d go with the only variant that wasn’t proposed yet :slight_smile: Which is:

Enum.map [1,2,3], &(&1 
                    |> is_integer 
                    |> is_integer)

Why?

  1. Because the outer Enum.map call is a single function call without piping, I call it directly.
  2. Because the code inside &() is a candidate to piping, I do that (as it should be preferred).
  3. Because final Enum.map spans multiple lines and it’s not piped, I omit parenthesis when calling it.

What do you think? :slight_smile:

5 Likes

I agree. This looks cleaner than the other styles mentioned. :ok_hand:

I suppose this is good if you are only use map.