You are hitting limitations related to type inference within member groups, since these groups are recusive. Try either defining your generic code in a separate module, or give it a complete type annotation, including type variable declarations, e.g.

member x.Read<'a>(request:HttpWebRequest, f:(XmlReader->'a)) : seq<'a> =
use response = request.GetResponse()
use stream = response.GetResponseStream()
use reader = XmlReader.Create(stream, xmlReaderSettings)
f(reader)

Regards

don

By on 6/26/2008 12:08 AM ()

My troubles went away after I switched this method to be just a function rather than a member.

let read(request:HttpWebRequest, f) =
use response = request.GetResponse()
use stream = response.GetResponseStream()
use reader = XmlReader.Create(stream, xmlReaderSettings)
f(reader)

I'm using System.Xml.Linq in the functions I'm passing in like so:

let xdoc = XDocument.Load(xmlReader)

Using Xml.Linq works great, but when I try to loop though the elements myself using XmlReader I'm having problems. I think the reader gets disposed before a yield happens. I'm not sure how to "Avoid Combing Imperative Programming and Lazyiness" in this situation. How come Linq works? Here is the some sample code showing Linq working and my XmlReader direct not:

#light
#r @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll"
open System.Xml
open System.Xml.Linq

let xmlStream(xml:string) =
new System.IO.MemoryStream( System.Text.Encoding.UTF8.GetBytes(xml) )

let read(xml:string, f) =
use stream = xmlStream(xml)
use reader = XmlReader.Create(stream)
f(reader)

let xname(name) = XName.op_Implicit(name)

let readNamesViaLinq(xmlReader:XmlReader) =
XDocument.Load(xmlReader).Descendants(xname("name")) |> Seq.map( fun xName -> xName.Value )

let readNamesViaReader(xr:XmlReader) = seq {
while xr.ReadToFollowing("name") do yield xr.ReadString() }

let namesXml = "<names><name>Don</name><name>Cameron</name><name>Bob</name><name>George</name></names>"
let namesViaLinq = read( namesXml, readNamesViaLinq)
let namesViaReader = read( namesXml, readNamesViaReader)

cheers,
Cameron

By on 6/26/2008 1:47 PM ()

In the ViaLinq case your "f" is returning a delayed computation (sequences are delayed, on-demand steams of values). The two "use" blocks in your "read" function dispose their resources immediately after "f" is called, before any elements are read off the sequence.

You should put all resource acquisitions inside the sequence expression, e.g.

1
2
3
4
5
6
7
 

let readOnDemand(xml:string, f) =
  seq { use stream = xmlStream(xml)
           use reader = XmlReader.Create(stream)
           yield! f(reader) }

This topic is covered further toward the end of Expert F#, chapter 4. Beware mixing laziness and side effects, though if you do it carefully it can be extremely powerful.

Kind regards

don

By on 6/27/2008 4:42 PM ()
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