I am learning about writing point free and things were going great until I ran into this:
let rec toSeq (reader : SqlDataReader) toItem = seq {
if reader.Read()
then
yield toItem reader
yield! toSeq reader toItem
else
yield! Seq.empty }
and this:
let execute sql init toItem =
seq {
use command = new SqlCommand(sql)
command |> init
use connection = new SqlConnection("")
connection.Open()
command.Connection <- connection
use reader = command.ExecuteReader()
yield! toSeq reader toItem } |> Seq.toList
I have no idea how to get past the sequence builder... Is this even possible?
I need to make sure the usings still work correctly as well.
FYI: I know it might seem pointless to use point free programming here. Just understand this is a learning exercise for me.
UPDATE: Here is my first attempt on the second function. I had to remove the sequence references though:
let ExecuteReader (command : SqlCommand) (connection : SqlConnection) =
command.Connection <- connection
command.ExecuteReader()
let c x y = ((>>) x) << ((<<) << y)
let (>>|) = c
let execute =
ExecuteReader
>>| ((>>) toSeq) (flip using)
>>| using
>>| using
Well, as already noted in the comments, writing imperative code in a point-free style is not a good idea at all. Not only it does not make it more readable, but it makes it more error-prone, because it is more difficult to reason about the execution. Even with functional code, I often find the non-point-free style a lot more readable (and not much longer).
Anyway, since you asked, here are some steps you can take - note that this is really an exercise in functional obfuscation. Not something you would ever want to do.
The code for the first function would be desugared to something like this (this is going to be less efficient because sequence expressions are optimized):
let rec toSeq (reader : SqlDataReader) toItem = Seq.delay (fun () ->
if reader.Read() then
Seq.concat [ Seq.singleton (toItem reader); toSeq reader toItem ]
else
Seq.empty)
Even in the point-free style, you still need the Seq.delay to make sure that you're executing the sequence lazily. However, you can define slightly different function that lets you write code in a more point-free style.
// Returns a delayed sequence generated by passing inputs to 'f'
let delayArgs f args = Seq.delay (fun () -> f args)
let rec toSeq2 : (SqlDataReader * (SqlDataReader -> int)) -> seq<int> =
delayArgs (fun (reader, toItem) ->
if reader.Read() then
Seq.concat [ Seq.singleton (toItem reader); toSeq2 (reader, toItem) ]
else
Seq.empty)
Now, the body of the function is just some function passed to the delayArgs function. We can try composing this function from other functions in a point-free style. The if is tricky though, so we replace it with a combinator that takes three functions (and passes the same input to all of them):
let cond c t f inp = if c inp then t inp else f inp
let rec toSeq3 : (SqlDataReader * (SqlDataReader -> int)) -> seq<int> =
delayArgs (cond (fun (reader, _) -> reader.Read())
(fun (reader, toItem) ->
Seq.concat [ Seq.singleton (toItem reader);
toSeq3 (reader, toItem) ])
(fun _ -> Seq.empty))
You cannot treat member invocations in a point-free style, so you need to define function that calls Read. Then you can also use a function that returns constant function (to avoid name collisions, named konst):
let read (reader:SqlDataReader) = reader.Read()
let konst v _ = v
Using the two, you can turn the last and the second argument to a point-free style:
let rec toSeq4 : (SqlDataReader * (SqlDataReader -> int)) -> seq<int> =
delayArgs (cond (fst >> read)
(fun (reader, toItem) ->
Seq.concat [ Seq.singleton (toItem reader);
toSeq4 (reader, toItem) ])
(konst Seq.empty))
Using some more crazy combinators (uncurry existis in Haskell; the list2 combinator could be also written in a point-free style, but I think you get the idea):
let list2 f g inp = List.Cons(f inp, List.Cons(g inp, []))
let uncurry f (a, b) = f a b
let rec toSeq5 : (SqlDataReader * (SqlDataReader -> int)) -> seq<int> =
delayArgs (cond (fst >> read)
(list2 ((uncurry (|>)) >> Seq.singleton) toSeq5 >> Seq.concat)
(konst Seq.empty))
This does not quite compile, because toSeq5 is evaluated as part of its definition, but if you insered some delay function, it might actually do the same thing as what it did originally.
Summary - I don't know anymore if the code above is correct and how it evaluates (it might evaluate the reader eagerly, or contain some other kind of bug). It does type-check, so it probably isn't too far from working. The code is completely unreadable, hard to debug and impossible to modify.
Think of this as an extreme example of crazy point-free code you can write in F#. In practice, I think that point-free style should only be used for trivial things like composing functions using >>. Once you need to define combinators like uncurry or konst, it will be really hard for people to read your code.
Related
I know there's the back-pipe (<|) operator, referenced in several other SO answers. But that doesn't work well when combined with forward pipes (|>), which is common in chaining. However I'm looking for related options. Basically is there any built-in version of the below function definition? Or is this a bad/dangerous practice?
let inline (^%) f = f
let stuff =
[1;2;3]
|> Seq.filter ^% (>) 2
|> Seq.map ^% fun x -> x.ToString()
// compare to this, which doesn't compile (and would be hard to follow even if it did)
let stuff =
[1;2;3]
|> Seq.filter <| (>) 2
|> Seq.map <| fun x -> x.ToString()
There are some Haskell features, like optional infixing using backticks, and sections, which aren't available in F#. That makes certain constructs a bit more verbose.
Usually, I'd simply write a pipe of functions as the above like this:
let stuff =
[1;2;3]
|> Seq.filter (fun x -> x < 2)
|> Seq.map string
This is, in my opinion, much more readable. For example, using Seq.filter ^% (>) 2, I'd intuitively read that as meaning 'all values greater than 2', but that's not what it does:
> let inline (^%) f = f;;
val inline ( ^% ) : f:'a -> 'a
> let stuff =
[1;2;3]
|> Seq.filter ^% (>) 2
|> Seq.map ^% fun x -> x.ToString()
|> Seq.toList;;
val stuff : string list = ["1"]
If you leave the reader of the code in doubt of what the code does, you've just made everyone less productive. Using Seq.filter (fun x -> x < 2) may look more verbose, but is unambiguous to the reader.
I'm trying to imitate Haskell's famous infinite fibonacci list in F# using sequences. Why doesn't the following sequence evaluate as expected? How is it being evaluated?
let rec fibs = lazy (Seq.append
(Seq.ofList [0;1])
((Seq.map2 (+) (fibs.Force())
(Seq.skip 1 (fibs.Force())))))
The problem is that your code still isn't lazy enough: the arguments to Seq.append are evaluated before the result can be accessed, but evaluating the second argument (Seq.map2 ...) requires evaluating its own arguments, which forces the same lazy value that's being defined. This can be
worked around by using the Seq.delay function. You can also forgo the lazy wrapper, and lists are already seqs, so you don't need Seq.ofList:
let rec fibs =
Seq.append [0;1]
(Seq.delay (fun () -> Seq.map2 (+) fibs (Seq.skip 1 fibs)))
However, personally I'd recommend using a sequence expression, which I find to be more pleasant to read (and easier to write correctly):
let rec fibs = seq {
yield 0
yield 1
yield! Seq.map2 (+) fibs (fibs |> Seq.skip 1)
}
To add to kvb's answer, you can also use Seq.unfold to generate a (lazy) sequence:
let fibs = Seq.unfold (fun (a, b) -> Some(a+b, (b, a+b))) (0, 1)
val fibs : seq<int>
Yet another way:
let rec fib = seq { yield 0; yield! Seq.scan (+) 1 fib }
In addition to #kvb's answer: if you just want lazy and not necessarily the zip trick, you can do this:
let fibs = Seq.unfold (fun (m,n) -> Some (m, (n,n+m))) (0,1)
This makes Seq.take n fibs run in time O(n).
So I have a function SolveEquasion that returns a pair float*float[]. What is the best way to print the number and the array and continue working with the array? I made the following code but it seems there is a better way
...
|> SolveEquasion
|> (fun (det, solution) -> printfn "Determinant = %f\nSolution = %A" det (Array.toList solution), solution )
|> snd
I don't think your solution can improved if you want to do this in a pipeline. Another approach is to use a let binding, along with splitting up the pipelined operations, to avoid having a function that acts like the love child of map and iter.
let (det, solution) = SolveEquasion
printfn "Determinant = %f\nSolution = %A" det (Array.toList solution)
//do something else with solution
I think the original solution is fine, and we can improve its clarity by giving your anonymous function the name I've seen it given in some other libraries based around pipelining higher-order functions: tap.
let tap f x =
f x
x
(1.0, [| 2.0; 3.0 |])
|> tap (fun (s, a) -> printfn "%A %A" s a)
|> snd
Well, for one thing you can skip the use of snd by returning a single value rather than a tuple from the previous function:
...
|> SolveEquasion
|> (fun (det, solution) ->
printfn "Determinant = %f\nSolution = %A" det (Array.toList solution)
solution )
I'd probably use Daniel's approach and just assign the value you want to print to a symbol using let. Alternatively, you could define a variant of printf that takes some arguments and returns one of them. I'm not sure if there is a general scheme how this should be done - for your example it would take a two-element tuple:
let mprintf fmt (a, b) =
Printf.kprintf (fun s -> printf "%s" s; (a, b)) fmt a b
Then you can write:
...
|> SolveEquasion
|> mprintfn "Determinant = %f\nSolution = %A"
|> snd |> // ... more stuff with solution
I am trying to build a list from a sequence by recursively appending the first element of the sequence to the list:
open System
let s = seq[for i in 2..4350 -> i,2*i]
let rec copy s res =
if (s|>Seq.isEmpty) then
res
else
let (a,b) = s |> Seq.head
Console.WriteLine(string a)
let newS = s |> Seq.skip(1)|> Seq.cache
let newRes = List.append res ([(a,b)])
copy newS newRes
copy s ([])
Two problems:
. getting a Stack overflow which means my tail recusive ploy sucks
and
. why is the code 100x faster when I put |> Seq.cache here let newS = s |> Seq.skip(1)|> Seq.cache.
(Note this is just a little exercise, I understand you can do Seq.toList etc.. )
Thanks a lot
One way that works is ( the two points still remain a bit weird to me ):
let toList (s:seq<_>) =
let rec copyRev res (enum:Collections.Generic.IEnumerator<_*_>) =
let somethingLeft = enum.MoveNext()
if not(somethingLeft) then
res
else
let curr = enum.Current
Console.WriteLine(string curr)
let newRes = curr::res
copyRev newRes enum
let enumerator = s.GetEnumerator()
(copyRev ([]) (enumerator)) |>List.rev
You say it's just an exercise, but it's useful to point to my answer to
While or Tail Recursion in F#, what to use when?
and reiterate that you should favor more applicative/declarative constructs when possible. E.g.
let rec copy2 s = [
for tuple in s do
System.Console.WriteLine(string(fst tuple))
yield tuple
]
is a nice and performant way to express your particular function.
That said, I'd feel remiss if I didn't also say "never create a list that big". For huge data, you want either array or seq.
In my short experience with F# it is not a good idea to use Seq.skip 1 like you would with lists with tail. Seq.skip creates a new IEnumerable/sequence and not just skips n. Therefore your function will be A LOT slower than List.toSeq. You should properly do it imperative with
s.GetEnumerator()
and iterates through the sequence and hold a list which you cons every single element.
In this question
Take N elements from sequence with N different indexes in F#
I started to do something similar to what you do but found out it is very slow. See my method for inspiration for how to do it.
Addition: I have written this:
let seqToList (xs : seq<'a>) =
let e = xs.GetEnumerator()
let mutable res = []
while e.MoveNext() do
res <- e.Current :: res
List.rev res
And found out that the build in method actually does something very similar (including the reverse part). It do, however, checks whether the sequence you have supplied is in fact a list or an array.
You will be able to make the code entirely functional: (which I also did now - could'nt resist ;-))
let seqToList (xs : seq<'a>) =
Seq.fold (fun state t -> t :: state) [] xs |> List.rev
Your function is properly tail recursive, so the recursive calls themselves are not what is overflowing the stack. Instead, the problem is that Seq.skip is poorly behaved when used recursively, as others have pointed out. For instance, this code overflows the stack on my machine:
let mutable s = seq { 1 .. 20001 }
for i in 1 .. 20000 do
s <- Seq.skip 1 s
let v = Seq.head s
Perhaps you can see the vague connection to your own code, which also eventually takes the head of a sequence which results from repeatedly applying Seq.skip 1 to your initial sequence.
Try the following code.
Warning: Before running this code you will need to enable tail call generation in Visual Studio. This can be done through the Build tab on the project properties page. If this is not enabled the code will StackOverflow processing the continuation.
open System
open System.Collections.Generic
let s = seq[for i in 2..1000000 -> i,2*i]
let rec copy (s : (int * int) seq) =
use e = s.GetEnumerator()
let rec inner cont =
if e.MoveNext() then
let (a,b) = e.Current
printfn "%d" b
inner (fun l -> cont (b :: l))
else cont []
inner (fun x -> x)
let res = copy s
printfn "Done"
Some background first. I am currently learning some stuff about monadic parser combinators. While I tried to transfer the 'chainl1' function from this paper (p. 16-17), I came up with this solution:
let chainl1 p op = parser {
let! x = p
let rec chainl1' (acc : 'a) : Parser<'a> =
let p' = parser {
let! f = op
let! y = p
return! chainl1' (f acc y)
}
p' <|> succeed acc
return! chainl1' x
}
I tested the function with some large input and got a StackOverflowException. Now I am wondering, is it posible to rewrite a recursive function, that uses some computation expression, in a way so it is using tail recursion?
When I expand the computation expression, I can not see how it would be generally possible.
let chainl1 p op =
let b = parser
b.Bind(p, (fun x ->
let rec chainl1' (acc : 'a) : Parser<'a> =
let p' =
let b = parser
b.Bind(op, (fun f ->
b.Bind(p, (fun y ->
b.ReturnFrom(chainl1' (f acc y))))))
p' <|> succeed acc
b.ReturnFrom(chainl1' x)))
In your code, the following function isn't tail-recursive, because - in every iteration - it makes a choice between either p' or succeed:
// Renamed a few symbols to avoid breaking SO code formatter
let rec chainl1Util (acc : 'a) : Parser<'a> =
let pOp = parser {
let! f = op
let! y = p
return! chainl1Util (f acc y) }
// This is done 'after' the call using 'return!', which means
// that the 'cahinl1Util' function isn't really tail-recursive!
pOp <|> succeed acc
Depending on your implementation of parser combinators, the following rewrite could work (I'm not an expert here, but it may be worth trying this):
let rec chainl1Util (acc : 'a) : Parser<'a> =
// Succeeds always returning the accumulated value (?)
let pSuc = parser {
let! r = succeed acc
return Choice1Of2(r) }
// Parses the next operator (if it is available)
let pOp = parser {
let! f = op
return Choice2Of2(f) }
// The main parsing code is tail-recursive now...
parser {
// We can continue using one of the previous two options
let! cont = pOp <|> pSuc
match cont with
// In case of 'succeed acc', we call this branch and finish...
| Choice1Of2(r) -> return r
// In case of 'op', we need to read the next sub-expression..
| Choice2Of2(f) ->
let! y = p
// ..and then continue (this is tail-call now, because there are
// no operations left - e.g. this isn't used as a parameter to <|>)
return! chainl1Util (f acc y) }
In general, the pattern for writing tail-recursive functions inside computation expressions works. Something like this will work (for computation expressions that are implemented in a way that allows tail-recursion):
let rec foo(arg) = id {
// some computation here
return! foo(expr) }
As you can check, the new version matches this pattern, but the original one did not.
In general it is possible to write tail-recursive computation expressions (see 1 and 2), even with multiple let! bindings thanks to the 'delay' mechanism.
In this case the last statement of chainl1 is what gets you into a corner I think.