--- THREAD CLOSED - Problem solved ---

Due to blafasel and cfern problem was solved successfully. Thanks a lot for your extensive explanations ! I think I got the F# concepts one step further.

(In addition I also tried to find a solution for hours and found a pretty much similar sample on a webcast presented by Tomas Petricek ([link:tomasp.net]). In this webcast he also deals with OOP concepts (FeedItem and FeedSearch instead of Person))

For completeness I post the mentioned code that was originally written by Tomas Petricek. I did some minor settings to run it in VS 2010 beta 2 especially using the async Microsoft.FSharp.Control.WebExtensions and Seq.ToList

//-------------------------------

//Content Reader.fs

//-------------------------------

module ContentReader

open System

open System.Net

open System.IO

open System.Xml

open System.Threading

open Microsoft.FSharp.Control

open Microsoft.FSharp.Control.WebExtensions

type FeedItem(title:string, description:string) =

member x.Title = title

member x.Description = description

type FeedSearch(feeds:seq<string>) =

let downloadUrl(url:string) = async {

let req = HttpWebRequest.Create(url)

let! rsp = req.AsyncGetResponse()

use rst = rsp.GetResponseStream()

use reader = new StreamReader(rst)

let str = reader.ReadToEnd()

return str }

let searchItems(feed:string, keywordArray) = async {

let! xml = downloadUrl(feed)

let doc = new XmlDocument()

doc.LoadXml(xml)

let items =

[ for nd in doc.SelectNodes("rss/channel/item") do

let title = nd.SelectSingleNode("title").InnerText

let descr = nd.SelectSingleNode("description").InnerText

yield new FeedItem(title, descr) ]

let result =

items

|> List.filter (fun item ->

keywordArray |> Array.exists (fun keyword ->

item.Title.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) > 0

|| item.Description.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) > 0))

return result }

member x.Search(keywords:string) =

let keywordsArray = keywords.Split(' ')

Async.RunSynchronously

(Async.Parallel([ for feed in feeds do

yield searchItems(feed, keywordsArray) ]))

|> List.concat

|> Seq.ofList

//-----------

//Program.fs

//----------

// Learn more about F# at [link:fsharp.net]

module Program

open ContentReader

[<EntryPoint>]

let main(args) =

let feeds =

[ "[link:blogs.msdn.com] ]

let start = new FeedSearch(feeds)

let result = start.Search("C#")

let feedItems = Seq.toList result

let filteredFeedItems = List.filter (fun (a:FeedItem) -> a.Title.Contains ("Ado")) feedItems

let cool = List.iter (fun (x:FeedItem) -> printfn "%s" x.Title) filteredFeedItems

0

By on 11/4/2009 12:44 AM ()

List.filter expects a filter function (you provided that one) and a list - and results in the filtered list again.

You "curried" the function: Given a function that takes 2 parameters (filter method, list) you provided the first one and got back a new function, that takes a list (input for List.filter) and returns the filter result.

I suggest you read about curried functions lateron and provide the list as a second parameter in that line for now - it should compile. I do have to admit that I didn't copy/compile/test the code though..

By on 11/3/2009 8:06 AM ()

As Blafasel already said, you need to provide all arguments to a function to get the result. Leaving an argument out results in another function that accepts the missing argument to get the result.

Another thing that seems strange about your code is the following line:

1
    let listOfImmutablePersons = List.iter (fun (b:Person) -> printfn "%s" b.Name) personList

The List.iter method means the same as a ForEach on an ArrayList. It performs an action and returns unit (this can be compared to void in C#). So if you inspect the type of listOfImmutablePersons, you'd get unit.

If you wanted to print the names of the people in personList, you could simply do

1
2
3
    List.iter (fun (b:Person) -> printfn "%s" b.Name) personList

But, if you wanted to store the names of the persons in listOfImmutablePersons, you'd need something similar to LINQ's Select, which is List.map:

1
    let listOfImmutablePersons = List.map (fun (b:Person) -> b.Name) personList

Another tip: try using the forward pipe operator (|>) in your code. I find that it helps visualize the stream of a computation. With the forward pipe, you can write down the last argument of a function and apply the rest. For example:

1
2
3
    let listOfImmutablePersons = List.map (fun (b:Person) -> b.Name) personList

would become

1
2
3
    let listOfImmutablePersons = personList |> List.map (fun (b:Person) -> b.Name)

another example:

1
    let immutablePersons = personList |> Seq.toList

It may seem a bit redundant now, but the real power of |> appears as soon as you start combining operations, perhaps like this:

1
2
3
4
5
    let filteredPersonsNames =
        personList
        |> Seq.toList
        |> List.filter (fun (i:Person) -> i.Name = "Singer Corporation")
        |> List.map (fun (b:Person) -> b.Name)

Hmm... this post turned out a bit longer than anticipated. I hope it helped.

By on 11/4/2009 12:11 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper