Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# passing none to function, getting null as parameter value

Tags:

.net

f#

This is really weird and I fear I have just done something dumb but I can't figure it out.

I'm passing None to the function some as the first parameter but when the function executes, the value of parentNode is null (I'm not concerned with it printing null for None, the function parameter value IS null not None). I end up getting a null reference error on the print function line because parentNode is null. I've tried to tuple the args and change the order but that didn't help. I have a sneaking suspicion that this has something to do with currying but I'm at a loss...

I had to replace the real url value with an empty string for company issues but it is a url to an xsd if that helps

Here is the code:

#light
open System
open System.Xml
open System.Net
open System.Collections.Generic

type StartResult =
    | Parameters of XsdParserParameters
    | Xsd of Xsd

and Xsd(text) =
    let rows = new List<string>()

    member this.Text
        with get() = text

    member this.Rows
        with get() = rows

and XsdParserParameters() =
    let mutable url = ""

    member this.Url
        with get() = url
        and set(value) = url <- value

    member this.Start() =
        try
            use client = new WebClient()
            let xsd = client.DownloadString(this.Url)
            StartResult.Xsd(Xsd(xsd))
        with e ->
            StartResult.Parameters(this)

let processor () =
    let parameters = XsdParserParameters()
    parameters.Url <- ""
    match parameters.Start() with
    | StartResult.Parameters(xpparams) ->
        //some error
        ()
    | StartResult.Xsd(xsd) ->

        let rec some (parentNode : XmlNode option) (node : XmlNode) =
            let a = ()

            for subNode in node.ChildNodes do
                match subNode.LocalName with
                | "complexType" ->
                    xsd.Rows.Add(
                        sprintf
                            "%O~%s~%d~%d~%s~%s~%O" 
                            parentNode 
                            subNode.Value 
                            1 
                            1 
                            (subNode.Attributes.GetNamedItem("name").Value)
                            "" 
                            false)
                    some (Some(subNode)) subNode 
                | "sequence" ->
                    some parentNode subNode 
                | "element" ->
                    xsd.Rows.Add(
                        sprintf 
                            "%O~%s~%d~%d~%s~%s~%O" 
                            parentNode 
                            subNode.Value 
                            1 
                            1 
                            (subNode.Attributes.GetNamedItem("name").Value) 
                            "" 
                            false)
                    some (Some(subNode)) subNode 
                | _ ->
                    ()

        let xdoc = new XmlDocument();
        xdoc.LoadXml(xsd.Text)

        some (None) (xdoc.DocumentElement)

processor()

printfn "Done..."
Console.ReadLine() |> ignore
like image 648
Brad Avatar asked May 03 '12 15:05

Brad


2 Answers

Unfortunately, it's the way F# prints out None:

> sprintf "%O" None;;
val it : string = "<null>"

You can easily write a custom sprintf function for option type, for example:

let sprintOption v = 
    if Option.isNone v then "None" else sprintf "%A" v
like image 182
pad Avatar answered Oct 31 '22 17:10

pad


Option<'T> (source on Github) uses the attribute [<CompilationRepresentation([CompilationRepresentationFlags.UseNullAsTrueValue)>] which causes the nullary case (None, in this instance) to be represented by null at run-time.

like image 29
Daniel Avatar answered Oct 31 '22 17:10

Daniel