Given a string of digits, I would like to have a sequence of tuples mapping the non-zero characters with their position in the string. Example:
IN: "000140201"
OUT: { (3, '1'); (4, '4'); (6, '2'); (8, '1') }
Solution:
let tuples = source
|> Seq.mapi (fun i -> fun c -> (i, c))
|> Seq.filter (snd >> (<>) '0')
It seems like (fun i -> fun c -> (i, c)) is a lot more typing than it should be for such a simple and presumably common operation. It’s easy to declare the necessary function:
let makeTuple a b = (a, b)
let tuples2 = source
|> Seq.mapi makeTuple
|> Seq.filter (snd >> (<>) '0')
But it seems to me that if the library provides the snd function, it should also provide the makeTuple function (and probably with a shorter name), or at least it should be relatively easy to compose. I couldn’t find it; am I missing something? I tried to build something with the framework’s Tuple.Create, but I couldn’t figure out how to get anything other than the single-argument overload.
F# assumes that you decompose tuples (using
fst,snd) much more often than composing them. Functional library design often follows minimal principle. Just provide functions for common use cases, other functions should be easy to define.No, you aren’t. It’s the same reason that FSharpPlus has defined
tuple2,tuple3, etc. Here are utility functions straight from Operators:F# compiler hides properties of
System.Tuple<'T1, 'T2>to enforce pattern matching idiom on tuples. See Extension methods for F# tuples for more details.That said, point-free style is not always recommended in F#. If you like point-free, you have to do a bit of heavy lifting yourself.