F#: String.Join and |> operator - f#

In F# interactive, I can use String.Join("+", ["a"; "b"]) successfully, but
["a"; "b"] |> String.Join "+"
produces an error:
Script1.fsx(79,15): error FS0001: This expression was expected to have type
string list -> 'a
but here has type
string
How do I use String.Join passing a collection using pipeline?
P.S. The same problem is with lines |> File.WriteAllLines "filename.txt"

String.Join is a .NET method. When using a .NET method, F# views it as a function that takes a tuple as an argument (when calling it you write parameters as f(a, b)). The |> operator can be used with functions that use the curried form of parameters (and can be called by writing f a b).
You can use a function String.concat from the F# library (which does the same thing) instead:
["a"; "b"] |> String.concat "+"
EDIT File.WriteAllLines is the same case. If you want to use it as part of a pipeline, you can write an F# function that wraps the call:
let writeAllLines file (lines:seq<string>) =
System.IO.File.WriteAllLines(file, lines)
In general, you can use |> with .NET methods only if you want to write all arguments on the left side of the operator. You can for example write:
("+", ["a"; "b"]) |> System.String.Join
... but that doesn't fit with the usual use of pipeline operator. When working with .NET API, it is usually better to use a C#-like style of programming (without pipelining), because pipeline works well only with functional libraries.

I thought I would weigh in with an alternative. The OP specifically asked about String.Join, and Tomas Petricek's answer is absolutely correct for that method (use String.concat from the F# library).
If you're talking about another method that takes tupled arguments but you want to use them as curried, you can use this helper function:
let partial f x y = f(x, y)
This allows you to pass a method to 'partial' and get back a curried function. Use it like this:
let partial f x y = f(x, y)
myCollection |> partial String.Join "&"

Related

Negate a string method in a lambda function gives error

I am calling the string method "contains" in a lambda function, and would like to negate it. I thought this could be done with not myString.Contains("abbr") but it gives me the error
Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized
My actual function is this
open System.IO
let createWordArray filePath =
File.ReadLines(filePath)
|> Seq.filter (fun line -> line <> "")
|> Seq.filter (fun line -> not line.Contains("abbr.")) // Error occurs here
|> Seq.map (fun line -> line.Split(' ').[0])
|> Seq.filter (fun word -> word.StartsWith("-") || word.EndsWith("-"))
|> Seq.toArray
Please point out any other obvious mistakes I'm making.
You just need to add parentheses around the argument of the not function:
|> Seq.filter (fun line ->
not (line.Contains("abbr.")))
Without the parentheses, the compiler is interpreteing your code as a call to not with two arguments:
not (line.Contains) ("abbr.")
F# syntax is not like C# (or C, or C++, or Java)
In particular, F# does not use parentheses for passing function arguments. Instead, F# uses whitespace for that:
let x = f y z
You are, of course, free to enclose any terms in parentheses if you wanted to indicate the order of operations, or just for aesthetic reasons:
let x = f (y+5) z // parens for order of operations
let x = f (y) (z) // parens just for the heck of it
So you see, when you write:
line.Contains("abbr.")
There is no special meaning to the parens. You could just as well write this:
line.Contains "abbr."
It would be equivalent.
See what's happening? Not yet? Well, ok, let's try to add the not to the mix:
not line.Contains "abbr."
Is it clearer now? This looks like you're trying to call the not function, and you're giving it two arguments: first argument is line.Contains, and the second argument is "abbr."
This is not what you meant, right? What you meant was probably to first call line.Contains passing it "abbr " as argument, and then pass the result of that to not
The most straightforward way to do this is to use parentheses to indicate the order of operations:
not (line.Contains "abbr.")
Or, alternatively, you could use operator <|, which is intended specifically for this kind of thing. It just passes a parameter to a function, so pretty much does nothing. But its point is that it's an operator, so it's precedence is lower than a function call:
not <| line.Cobtains "abbr."

Why data parameter comes last

Why have the data parameter in F# to come last, like the following code snippet shows:
let startsWith lookFor (s:string) = s.StartsWith(lookFor)
let str1 =
"hello"
|> startsWith "h"
I think part of your answer is in your question. The |> (forward pipe) operator lets you specify the last parameter to a function before you call it. If the parameters were in the opposite order, then that wouldn't work. The best examples of the power of this are with chaining of functions that operate on lists. Each function takes a list as its last parameter and returns a list that can be passed to the next function.
From http://www.tryfsharp.org/Learn/getting-started#chaining-functions:
[0..100]
|> List.filter (fun x -> x % 2 = 0)
|> List.map (fun x -> x * 2)
|> List.sum
The |> operator allows you to reorder your code by specifying the last
argument of a function before you call it. This example is
functionally equivalent to the previous code, but it reads much more
cleanly. First, it creates a list of numbers. Then, it pipes that list
of numbers to filter out the odds. Next, it pipes that result to
List.map to double it. Finally, it pipes the doubled numbers to
List.sum to add them together. The Forward Pipe Operator reorganizes
the function chain so that your code reads the way you think about the
problem instead of forcing you to think inside out.
As mentioned in the comments there is also the concept of currying, but I don't think that is as easy to grasp as chaining functions.

f# signature matching explained

I am running into difficulty with F# in numerous scenarios. I believe I'm not grasping some fundamental concepts. I'm hoping someone can track my reasoning and figure out the (probably many) things I'm missing.
Say I'm using Xunit. What I'd like to do is, provided two lists, apply the Assert.Equal method pairwise. For instance:
Open Xunit
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 Assert.Equal test1 test2
The compiler complains that the function Equal does not take one parameter. As far as I can tell, shouldn't map2 be providing it 2 parameters?
As a sanity check, I use the following code in f# immediate:
let doequal = fun x y -> printf "result: %b\n" (x = y)
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 doequal test1 test2;;
This seems identical. doequal is a lambda taking two generic parameters and returning unit. List.map2 hands each argument pairwise into the lambda and I get exactly what I expected as output:
result: true
result: true
result: false
So what gives? Source shows Xunit.Equal has signature public static void Equal<T>(T expected, T actual). Why won't my parameters map right over the method signature?
EDIT ONE
I thought two variables x and y vs a tuple (x, y) could construct and deconstruct interchangeably. So I tried two options and got different results. It seems the second may be further along than the first.
List.map2 Assert.Equal(test1, test2)
The compiler now complains that 'Successive arguments should be separated spaces or tupled'
List.map2(Assert.Equal(test1, test2))
The compiler now complains that 'A unique overload method could not be determined... A type annotation may be needed'
I think that part of the problem comes from mixing methods (OO style) and functions (FP style).
FP style functions have multiple parameters separated by spaces.
OO style methods have parens and parameters separated by commas.
Methods in other .NET libraries are always called using "tuple" syntax (actually subtly different from tuples though) and a tuple is considered to be one parameter.
The F# compiler tries to handle both approaches, but needs some help occasionally.
One approach is to "wrap" the OO method with an FP function.
// wrap method call with function
let assertEqual x y = Assert.Equal(x,y)
// all FP-style functions
List.map2 assertEqual test1 test2
If you don't create a helper function, you will often need to convert multiple function parameters to one tuple when calling a method "inline" with a lambda:
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2
When you mix methods and functions in one line, you often get the "Successive arguments should be separated" error.
printfn "%s" "hello".ToUpper()
// Error: Successive arguments should be separated
// by spaces or tupled
That's telling you that the compiler is having problems and needs some help!
You can solve this with extra parens around the method call:
printfn "%s" ("hello".ToUpper()) // ok
Or sometimes, with a reverse pipe:
printfn "%s" <| "hello".ToUpper() // ok
The wrapping approach is often worth doing anyway so that you can swap the parameters to make it more suitable for partial application:
// wrap method call with function AND swap params
let contains searchFor (s:string) = s.Contains(searchFor)
// all FP-style functions
["a"; "b"; "c"]
|> List.filter (contains "a")
Note that in the last line I had to use parens to give precedence to contains "a" over List.filter
public static void Equal<T>(T expected, T actual)
doesn't take two parameters - it takes one parameter, which is a tuple with two elements: (T expected, T actual).
Try this instead:
List.map2 Assert.Equal(test1, test2)
It's all there in the type signatures.
The signature for Assert.Equals is something along the lines of 'a * 'a -> unit. List.map2 expects a 'a -> 'b -> 'c.
They just don't fit together.
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2 - works because the lambda wrapping Equals has the expected signature.
List.zip test1 test2 |> List.map Assert.Equal - works because you now have a single list of tuples, and since List.map wants an 'a -> 'b function (where 'a is now a tuple), Assert.Equal is now fair game.
It's simply not true that two values and a tuple are implicitly interchangeable. At least not as far as F# the language is concerned, or the underlying IL representation is concerned. You can think that it's that way when you call into F# code from, say, C# - an 'a -> 'b -> 'c function there is indeed called the same way syntactically as an 'a * 'b -> 'c function - but this is more of an exception than a rule.
According to its signature Xunit.Assert.Equal() takes a single 2 values tuple parameter

Right associative operator in F# [duplicate]

This question already has an answer here:
Function Application Operator ($) in F#?
(1 answer)
Closed 8 years ago.
Sometimes I have to write:
myList |> List.iter (fun x -> x)
I would really like to avoid the parentheses. In Haskell there is an operator for this ($)
It would look like this
myList |> List.iter $ fun x -> x
I created a custom operator
let inline (^!) f a = f a
and now I can write it like this
myList |> List.iter ^! fun x -> x
Is there something like this in F#?
There is no way to define custom operator with an explicitly specified associativity in F# - the associativity is determined based on the symbols forming the operator (and you can find it in the MSDN documentation for operators).
In this case, F# does not have any built-in operator that would let you avoid the parentheses and the idiomatic way is to write the code as you write it originally, with parentheses:
myList |> List.iter (fun x -> x)
This is difference in style if you are coming from Haskell, but I do not see any real disadvantage of writing the parentheses - it is just a matter of style that you'll get used to after writing F# for some time. If you want to avoid parentheses (e.g. to write a nice DSL), then you can always named function and write something like:
myList |> List.iter id
(I understand that your example is really just an example, so id would not work for your real use case, but you can always define your own functions if that makes the code more readable).
No, there's nothing like this in a standard F# library. However, you have almost done creating your own operator (by figuring out its name must start with ^).
This snippet by Stephen Swensen demonstrates a high precedence, right associative backward pipe, (^<|).
let inline (^<|) f a = f a
This single-liner from the linked page demonstrates how to use it:
{1..10} |> Seq.map ^<| fun x -> x + 3
And here is an example how to use it for multi-line functions. I find it most useful for real-world multi-liners as you no longer need to keep closing parenthesis at the end:
myList
|> List.map
^<| fun x ->
let ...
returnValue
In F# it's <|
So it would look like:
myList |> List.iter <| fun x -> x

Piping, Composition, and Currying

It seems to me that all of these are related. What is the difference?
Piping is used to perform a sequence of operations on some value (just like piping in Unix). The input to each function is the output of the previous function. Obviously this requires each function take a single arg.
Composition (<< / >>) is similar in that it calls two functions in sequence (i.e., the output of the first is the input to the second) but it returns a function instead of immediately invoking the sequence.
Currying creates a new function by applying 1 to N-1 args to a function of N args
So, composition and currying are used to create functions whereas piping is used for invocation. Composition and currying differ in the way they create new functions (by applying args vs chaining).
In addition to what Daniel wrote, there is a very close correspondence between piping (the |> and <| operators) and function composition (the >> and << operators).
When you use piping to pass some data to a seqence of functions:
nums |> Seq.filter isOdd
|> Seq.map square
|> Seq.sum
... then this is equivalent to passing the input to a function obtained using function composition:
let composed =
Seq.filter isOdd
>> Seq.map square
>> Seq.sum
composed nums
In practice, this often means that you can replace function declaration that uses piping on the argument with a composition of functions (and use the fact that functions can be used as values). Here is an example:
// Explicit function declaration
foo (fun x -> x |> bar |> goo)
// Equivalent using function composition
foo (bar >> goo)

Resources