views:

617

answers:

3

While digging deeper into the latest release of F# I tried to have it interacting with PLINQ. I've noticed, however, that the two don't play very nice together code-wise. In fact it didn't seem possible to write code such as the following:


open System.Linq
let someArray = [|"abc"; "def"|]
someArray.AsParallel().Count(new Func<_,_>(fun s -> s.Length = 3))

because the extension methods for ParallelQuery contained in the System.Linq.ParallelEnumerable class didn't seem to get picked up by F#.
I wouldn't be surprised if there were no support for extension methods at all, but since I can access the someArray.Count extension method defined for IEnumerable I wonder why can't I access those of PLINQ.
Am I missing something?
Is this an F# limitation? If so, is it by desing? If not, will it be addressed in a future release?

+1  A: 

If I remember correctly, getting PLINQ to work nicely with F# is on the to-do list of the development team at Microsoft, though I'm not sure it will appear in .NET 4.0. F# does however have Asynchronous Workflows, which is very similar to PLINQ (except it's based around list comprehensions instead, which is the standard functional way of doing things). I can't seem to find the article that mentions better support in F# for the Parallel Extensions (PLINQ/TPL), so don't quote me on it, but I'm pretty sure I saw it somewhere.

Apart from the MSDN page, this article seems like a good introduction to the topic.

There's also this blog series (Using PLINQ in F#) that might be handy to read if you prefer to use PLINQ over Async Workflows still.

Noldorin
I know about Asynchronous Workflows but in several cases they're definitely not quite as handy as PLINQ. Also, would you please link me the source stating that PLINQ + F# is on schedule? Finally why would extension methods work in one case (IEnumerable<T>) and break in another one?
emaster70
Yeah, I agree that PLINQ offers greater scope and functionality in some situations. Post is updated.
Noldorin
+2  A: 

If you're not yet using .NET 4.0, you can write that as:

#r "System.Threading"
open System.Linq

let someArray = [|"abc"; "def"|]

someArray.AsParallel<string>()
|> Seq.filter (fun s -> s.Length = 3)
|> Seq.length

Come .NET 4.0, you can just write:

let someArray = [|"abc"; "def"|]

someArray
|> Array.Parallel.filter (fun s -> s.Length = 3)
|> Array.length

F# prefers the use of the Seq module over Linq extension methods. There are some helper functions available, however, in the FSharp.PowerPack.Linq assembly.

Ray Vernagus
Although one can't call choose that way because its signature is ('T -> 'U option) -> 'T array -> 'U array you gave me the solution: specifying the type in AsParallel. In fact it looks like otherwise the non-generic version was being returned. Finally, I know that Seq, Array and other modules are preferred in F# but in several circumstances one might rather start with something that's not an array or might want something that Array.Parallel doesn't offer.
emaster70
My bad, this will not do. While after using AsParallel<string> the extension methods are picked up, the compiler can't resolve the proper overload so it's useless :(
emaster70
I apologize about the Array.choose error. I caught that shortly after I posted but you found it before I edited it to the correct version. ;)FYI-in F#, the Seq module deals with any IEnumerable and the seq type is synonymous with IEnumerable.
Ray Vernagus
The compiler *can* resolve the proper overload, you just have to help it:(someArray.AsParallel<string>() :> IEnumerable<string>).Count()I agree, it's very unwieldy but better support for things like this is exactly what we can expect in an F# 2.0. I do encourage new F#'rs to get used to the Module way of coding, however, since this is likely to always be preferred over imperative styles.
Ray Vernagus
I knew about the IEnumerable <-> Seq and to be honest I like the module style much better (couple that with the pipeline operator and you can rule the world) but the lack of an official module exposing what PLINQ offers makes me look into using PLINQ the usual way. I've also found a post by some guy implementing a PSeq module, but using it my performances got a 35% cut which I didn't really like...
emaster70
+1  A: 

Extension methods are just statics that take the object as the first parameter, so you should be able to call it with

ParallelEnumerable.AsParallel(someArray).Count(...)
Ganesh Sittampalam