F# can't invoke Seq.fold without piping? - f#

I'm busy learning F# and was playing around with Seq.fold. Could anyone explain why the following two invocations are not essentially the same and one errors and the other does not.
Invoking this way:
Seq.fold (fun state input -> state + input) 0 Seq.ofList [1;2;3;4;5];;
Results in the following error:
error FS0001: This expression was expected to have type
''a -> 'b'
but here has type
'int'
Invoking with piping works fine:
Seq.ofList [1;2;3;4;5] |> Seq.fold (fun state input -> state + input) 0;;
I'm guessing I've somehow taken a generic function and forced it to be int only.

You're passing Seq.ofList as the 3rd parameter to Seq.fold. You need to add some parens:
Seq.fold (fun state input -> state + input) 0 (Seq.ofList [1;2;3;4;5]);;

Seq.ofList is not mandatory.
You can directly write:
Seq.fold (fun state input -> state + input) 0 [1;2;3;4;5]
or:
[1;2;3;4;5] |> Seq.fold (fun state input -> state + input) 0

Related

why does Seq.isEmpty say not enough elements?

nums is indeed seq of int when I mouse over. Any idea what's going on?
This function line is intended to be the equivalent of C#'s DefaultIfEmpty Linq function.
The general idea is take a space delimited line of strings and write out which ones occur count number of times.
code:
open System
[<EntryPoint>]
let main argv =
let tests = Console.ReadLine() |> int
for i in [0..tests] do
let (length, count) = Console.ReadLine()
|> (fun s -> s.Split [|' '|])
|> (fun split -> Int32.Parse(split.[0]), Int32.Parse(split.[1]))
Console.ReadLine()
|> (fun s -> s.Split [|' '|])
|> Seq.map int
|> Seq.take length
|> Seq.groupBy (fun x -> x)
|> Seq.map (fun (key, group) -> key, Seq.sum group)
|> Seq.where (fun (_, countx) -> countx = count)
|> Seq.map (fun (n, _) -> n)
|> (fun nums -> if Seq.isEmpty nums then "-1" else String.Join(" ", nums))
|> Console.WriteLine
0 // return an integer exit code
Sample input:
3
9 2
4 5 2 5 4 3 1 3 4
So, sequences in F# use lazy evaluation. That means that when you use functions such as map, where, take etc, the results are not evaluated immediately.
The results are only evaluated when the sequence is actually enumerated. When you call Seq.isEmpty you trigger a call to MoveNext() which results in the first element of the result sequence being evaluated - in your case this results in a large chain of functions being evaluated.
In this case, the InvalidOperationException is actually being triggered by Seq.take which throws if the sequence doesn't have sufficient elements. This might surprise you coming from C# where Enumerable.Take will take up to the requested number of elements but could take fewer if you reach the end of the sequence.
If you want this behaviour in F#, you need to replace Seq.take with Seq.truncate.

Combining functions with the same, but partially unknown signature

Suppose we have a number of filter functions that accept the same parameters and return a boolean result.
let filter1 _ _ = true
let filter2 _ _ = false
These can be combined into a single filter.
let combine2 f1 f2 = fun a b -> f1 a b && f2 a b
combine2 filter1 filter2
Our implementation requires some knowledge of the parameters of f1 and f2. More generally, we may find functions combine1 ... combineN useful, where N is the number of parameters to the filter functions. Can a generic combine function be written that is independent of N?
I am interested in the capabilities of F# and being able to apply this concept in other situations.
Update: My understanding of the problem is that functions succeed in ignoring any remaining parameters when they don't care whether the result is a simple type or a partially applied function. In the example above, we only reach a boolean type after applying all parameters, so they need to be specified.
use high order function, passing the function as argument
let combineN invoke filters = filters |> List.map invoke |> List.reduce (&&)
and use it like this
[filter1; filter2] |> combineN (fun f -> f 1 2) |> printfn "%b"
demo: https://dotnetfiddle.net/EHC5di
you can also pass List.reduce parameter as argument, like combineN (&&) (fun f -> f 1 2)
but usually is easier to write List.map |> List.reduce
you can also use it with more arguments
let filter3 _ _ _ = true
let filter4 _ _ _ = true
[filter3; filter4] |> List.map (fun f -> f 1 2 3) |> List.reduce (&&) |> printfn "%b"
[filter3; filter4] |> combineN (fun f -> f 1 2 3) |> printfn "%b"
compiler will check types (number arguments)
//call list of function with 2 argument, with more arguments doesnt compile
[filter1; filter2] |> combineN (fun f -> f 1 2 3) |> printfn "%b"
//mix functions with different arguments, doesnt compile either
[filter1; filter3] |> combineN (fun f -> f 1 2 3) |> printfn "%b"
see demo

Define sum of square without defining parameter

I want to define sumOfSquares without explicity using parameter, relying instead on functional composition
Here's my code below
let sumOfSquares = Seq.map (fun n -> n * n) >> Seq.sum
However, I got the following error
stdin(80,5): error FS0030: Value restriction. The value 'sumOfSquares'
has been inferred to have generic type
val sumOfSquares : ('_a -> int) when '_a :> seq<int>
Either make the arguments to 'sumOfSquares' explicit or, if you do not intend for
it to be generic, add a type annotation.
One way to resolve it is by using parameters
let sumOfSquares nums = nums |> Seq.map (fun n -> n * n) |> Seq.sum
and this will work. However, I want to see if I can define sum of squares by using composition alone
Update
Here's a nice article describing the issue I've encountered: Value Restriction.
Make a type annotation:
let sumOfSquares : seq<int> -> int =
Seq.map (fun n -> n * n) >> Seq.sum
So lets see what happens when the type inference tries to work here. First you have
Seq.map (fun n -> n * n) >> Seq.sum
Now as Seq allows for anything that implements Seq, we can input int list int[] or many others.
As a result, you get this as the type
val sumOfSquares : ('_a -> int) when '_a :> seq<int>
Now the problem is that sumofSquares is a value (which is a function). Unfortunately, you can't have a generic value in a top level binding. You can though have a generic function, if you make the arguments explicit.
As a result, one alternative to a type annotation is to make the argument explicit like so
let sumOfSquares s= s |> Seq.map (fun n -> n * n) |> Seq.sum
And this works
Searching SO for "value restriction errors" should give some more examples of this problem.

How to rewrite this function using the pipeline operator

These are the function definitions.
func1: 'a -> unit
func2: 'b -> 'a
func3: string -> 'b list
The current function
let f = Seq.iter((fun a -> func1(func2 a)) func3(s)
This is as far as I got
let f = func3(s)
|> ((fun a -> func2 a
|> func1)
|> Seq.iter)
I have the feeling it should be possible to loose the lambda and the parens'.
You can do without pipes, simply
Seq.iter (func1 << func2) << func3
(this is a function with some arguments [same than func3] and same output than Seq.iter).
You can test it
let func1 x = printfn "Number: %d" x
let func2 (a, b) = a + b
let func3 = Seq.map (fun n -> (n, 2 * n))
let f : (seq<_> -> unit) = Seq.iter (func1 << func2) << func3
f [1..5]
with output
Number: 3
Number: 6
Number: 9
Number: 12
Number: 15
val func1 : x:int -> unit
val func2 : a:int * b:int -> int
val func3 : (seq<int> -> seq<int * int>)
val f : (seq<int> -> unit)
val it : unit = ()
:)
You can use function composition operator >>:
func3() |> Seq.iter (func2 >> func1)
I think the question is, why do you want to use the pipeline operator?
I find your original code quite readable. You should not try to use pipeline operator (or function composition) just for the sake of using them. Now, in your code, the input s comes at the end, which is a bit unfortunate (you cannot quite see what is the main input for the code). I would probably rewrite it as (also, s is not really a descriptive name):
s |> func3
|> Seq.iter (fun a -> func1 (func2 a))
You can use function composition too - but I do not use it very often, because it does not (always) help with readability. But using it in the argument of Seq.iter is probably quite reasonable.
On a completely unrelated note, you could just use for loop and write:
for a in func3 s do
func1 (func2 a)
I actually find this more readable than any other version of the code here (if F# gives you a language feature for iterating over sequences that does exactly what you need, why not use it?)

F# Pipelines access data from pipeline stages above

I have written a function like this
let GetAllDirectAssignmentsforLists (spWeb : SPWeb) =
spWeb.Lists
|> Seq.cast<SPList>
|> Seq.filter(fun l -> l.HasUniqueRoleAssignments)
|> Seq.collect (fun l -> l.RoleAssignments
|> Seq.cast<SPRoleAssignment>
|> Seq.map(fun ra -> ra.Member)
)
|> Seq.filter (fun p -> p.GetType().Name = "SPUser")
|> Seq.map(fun m -> m.LoginName.ToLower())
I want to return a tuple which contains the list name (taken from l.Title) in the send pipe and the m.LoginName.ToLower().
Is there a cleanway for me to get something from the above pipe elements?
One way ofcourse would be to tuple the return value in the 2nd stage of the pipe and then pass the Title all the way down.... but that would pollute the code all subsequent stages will then have to accept and return tuple values just for the sake of the last stage to get the value.
I wonder if there is a clean and easy way....
Also, in stage 4 of the pipeline (fun p -> p.GetType().Name = "SPUser") could i use if here to compare the types? rather than convert the typename to string and then match strings?
We exploit the fact that Seq.filter and Seq.map can be pushed inside Seq.collect without changing the results. In this case, l is still available to access.
And the last filter function is more idiomatic to use with type test operator :?.
let GetAllDirectAssignmentsforLists(spWeb: SPWeb) =
spWeb.Lists
|> Seq.cast<SPList>
|> Seq.filter (fun l -> l.HasUniqueRoleAssignments)
|> Seq.collect (fun l -> l.RoleAssignments
|> Seq.cast<SPRoleAssignment>
|> Seq.map (fun ra -> ra.Member)
|> Seq.filter (fun p -> match box p with
| :? SPUser -> true
| _ -> false)
|> Seq.map (fun m -> l.Title, m.LoginName.ToLower()))
To simplify further, you could change the series of Seq.map and Seq.filter to Seq.choose:
Seq.choose (fun ra -> match box ra.Member with
| :? SPUser -> Some (l.Title, ra.Member.LoginName.ToLower())
| _ -> None)
While you can solve the problem by lifting the rest of the computation inside collect, I think that you could make the code more readable by using sequence expressions instead of pipelining.
I could not run the code to test it, but this should be equivalent:
let GetAllDirectAssignmentsforLists (spWeb : SPWeb) = seq {
// Corresponds to your 'filter' and 'collect'
for l in Seq.cast<SPList> spWeb.Lists do
if l.HasUniqueRoleAssignments then
// Corresponds to nested 'map' and 'filter'
for ra in Seq.cast<SPRoleAssignment> l.RoleAssignments do
let m = ra.Member
if m.GetType().Name = "SPUser" then
// This implements the last 'map' operation
yield l.Title, m.LoginName.ToLower() }
The code above corresponds more closely to the version by #pad than to your original code, because the rest of the computation is nested under for (which corresponds to nesting under collect) and so you can see all variables that are already in scope - like l which you need.
The nice thing about sequence expressions is that you can use F# constructs like if (instead of filter), for (instead of collect) etc. Also, I think it is more suitable for writing nested operations (which you need here to keep variables in scope), because it remains quite readable and keeps familiar code structure.

Resources