6

It's not a practically important issue, but I'd like to see an example of tacit programming in F# where my point-free functions can have multiple arguments (not in form of a list or tuple).

And secondly, how such functions can manipulate a complex data structure. I'm trying it out in F# Interactive, but have no success yet.

I tried, for instance:

> (fun _ -> (fun _ -> (+))) 333 222 111 555

Is that right way?

And:

> (fun _ -> (fun _ -> (+))) "a" "b" "c" "d";;  

val it : string = "cd"
Abel
  • 56,041
  • 24
  • 146
  • 247
Bubba88
  • 1,910
  • 20
  • 44

2 Answers2

4

F# doesn't contain some of the basic functions that are available in Haskell (mainly because F# programmers usually prefer the explicit style of programming and use pointfree style only in the most obvious cases, where it doesn't hurt readability).

However you can define a few basic combinators like this:

// turns curried function into non-curried function and back
let curry f (a, b) = f a b
let uncurry f a b = f (a, b)

// applies the function to the first/second element of a tuple
let first f (a, b) = (f a, b)
let second f (a, b) = (a, f b)

Now you can implement the function to add lengths of two strings using combinators as follows:

let addLengths = 
  uncurry (( (first String.length) >> (second String.length) ) >> (curry (+)))

This constructs two functions that apply String.length to first/second element of a tuple, then composes them and then adds the elements of the tuple using +. The whole thing is wrapped in uncurry, so you get a function of type string -> string -> int.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • I've checked that in FSI and it does work! Thank you very much; btw, could you explain how did you get to that tuple-function composition syntax? I mean `(first String.length) >> (second String.length)` It looks somewhat unusual to me ;) – Bubba88 May 08 '10 at 17:53
  • That's achieved using function composition `>>`. For example `f >> g` means that for an argument `x`, it will call `g(f(x))`. In the case above, the first function (`first String.length`) turns a tuple `string * string` into a tuple `int * string` and the second function (`second String.length`) turns this into `int * int` containing the lengths. – Tomas Petricek May 08 '10 at 18:02
  • You're practically implementing arrows for F# ;) Okay, why not - Arrows have been invented as a combination of monads and tacit programming. – Dario Aug 10 '10 at 15:30
2

In F#, the arity of functions is fixed, so you're not going to be able to write both

(op) 1 2

and

(op) 1 2 3 4

for any given operator op. You will need to use a list or other data structure if that's what you want. If you're just trying to avoid named variables, you can always do "1 + 2 + 3 + 4". The most idiomatic way to add a list of numbers in F# is List.sum [1;2;3;4], which also avoids variables.

kvb
  • 54,864
  • 2
  • 91
  • 133