Using LINQ in F#?
Given that the basic syntax and semantics of a language like F# are already designed to provide exactly what LINQ provides to C#/VB as an add one, why should I be using LINQ when pro开发者_JAVA百科gramming in F#? What do I gain, and what might I lose?
There are kind of two aspects to LINQ. One is the language side, e.g. in C# there are (contextual) keywords like from
and select
and where
you can use to author rather-SQL-like code that does queries over IEnumerable
s and whatnot. This is a relatively thin syntax sugar layer that transforms into LINQ library calls to Select
and SelectMany
and Where
and whatnot.
Then there's the IQueryable
aspect, which enables this same code to be reified as an IQueryable
, which is effectively much like a quotation mechanism, in that it kind of reifies the syntax tree that constructed the query. And that is essential, because then different providers can plug in behavior to 'compile' the code in their own way, e.g. a SQL provider can get a 'whole query' view and compose a query with a good query plan that will run on the server (as opposed to the naive approach of treating a SQL database as an IEnumerable
of rows and just loading all the rows in memory and filtering them in .NET inside your client app, which would perfom badly or simply fall down on large data).
The first aspect is just syntax sugar and whatnot. F# 2.0 (the F# version in VS2010) has no intrinsic support for LINQ, but the PowerPack has a LINQ bridge so that you can use F# quotations of normal F# Seq
combinators as a way to express LINQ queries.
The second aspect is the more essential bit in terms of the overall technology, though. LINQ is about reifying queries so that programmers can declaratively specify intent, and then various providers can plug into the system and translate that intent into an efficient execution plan for the corresponding backing store of data. The .NET 3.5. expression tree types are 'the interface' to this essential aspect of LINQ, and so any given programming language just needs some way for programmers to write expressions that will generate these expression trees.
So I don't feel like the original question quite makes sense. The essential reason to use LINQ is because you want to query a SQL database (or an OData feed, or ...) in such a way that the query runs efficiently on the server (or does not needlessly use a million repetitive HTTP requests, or ...), and you want to do so in a way that does not require you to know much about the details of those technologies (the various LINQ back-end providers have all the individual domain-specific smarts). The syntax is mostly just syntax, and different languages may have different sugars (or sugaring mechanisms) to author LINQ queries in ways that are idiomatic to a given programming language.
LINQ, from a language perspective (C#'s special from... syntax) is mostly unnecessary since F# is able to represent LINQ-like data transformations very succinctly already. I suspect that much of the remaining purpose of the C# sugar is to reorganize the code so C# can type LINQ queries without forcing the user to provide type annotations or perform eta-expansion manually. This, too, is unnecessary in F#.
As for using the System.Linq namespace in F#, I don't recommend it. F# type inference becomes extra stupid around member access. I suspect that using System.Linq would require more explicit type annotations than using the corresponding F# library. Even in cases where type inference succeeds, uncurried CLR-style API generally feels heavy and out-of-place in F# compared to the native libraries.
I agree with @blucz answer, it's not recommended, but if you really want, it looks like this:
Import System
and System.Linq
open System
open System.Linq
Wrap some LINQ
extension methods
let select f xs = Enumerable.Select(xs, new Func<_,_>(f))
let where f xs = Enumerable.Where(xs, new Func<_,_>(f))
let orderBy f xs = Enumerable.OrderBy(xs, new Func<_,_>(f))
And use it
[1..100]
|> where (fun x -> x > 2)
|> select (fun x -> x * 2)
|> printfn "%A"
You're right that for in-memory collections F# provides much of the behavior found in LINQ through the various collection modules, Seq
, List
, and the like. I believe LINQ's distinguishing feature is the plug-ability of query providers. While F# offers limited metaprogramming support through quotations, there's no trivial way that I'm aware of to translate these to something meaningful for disparate backing stores (PowerPack offers some support for this in F#).
To answer your question, if you intend to translate the queries instead of executing them against in-memory collections, LINQ is your best option. Otherwise, stick with the F# collection modules. By using LINQ when these suffice, you sacrifice partial function application, function chaining (piping), and you will write non-idiomatic code (there may be other pitfalls).
精彩评论