Maybe this help.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#light
open System

type node = class
    val mutable name: String
    val mutable next : node option 
    val mutable prev : node option
    new(objName) = {name = objName; next = None; prev = None} 
end

let node1 = new node("node1")
node1.next <- Some(new node("node2"))
let rec printNodes (x:node) =   Console.WriteLine(x.name)
                                match x.next with
                                | None -> Console.WriteLine("Finish")
                                | Some(n) -> printNodes n
                                
printNodes node1
Console.ReadLine()
By on 9/15/2007 2:14 AM ()

Thanks ais, I did not know about this type. Incidentally, I came back to my code 15mins ago having had the stunning revelation that all i needed to do in order to solve the problem (as above) was just to generalize my 'option' code so that is was not type specific and then my mutually dependent types would no longer be a problem.. but it looks like thats just what the real option type does! I wish I had found this earlier, come to think of it there is a Haskell type called Maybe, ( maybe a = Nothing | Just a ) ... grr what a fool I am!

By on 9/15/2007 7:04 AM ()

The syntax for classes used above is the "explicit" construction syntax. There is now a strong tendency to use the "implicit" construction syntax (Eventually we expect the explicit syntax to be really only used for code generation toolls like CodeDom. One current limitation make this harder: the limitation on mutually recursive classes using the implicit syntax referred to in a recent post on these forums)

For the "option", why not just use an option?

Here's one example:

1
2
3
4
5
6
7
8
type Node(name:string) = 
    // internal state
    let mutable next : Node option = None
    let mutable prev : Node option = None
    // external state
    member n.Value = name
    member n.Next with get() = next and set(v) = next <- v
    member n.Prev with get() = prev and set(v) = prev <- v

This approach lets you choose how you present the internal state externally. For example you might choose to publish properties that check for the First (no prev) and Last (no tail) conditions, and then Next and Prev would just derefence through the option values, which can save a lot of case analysis by client code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Node(name:string) = 
    // internal state
    let mutable next : Node option = None
    let mutable prev : Node option = None
    // external state
    member n.Name = name
    member n.IsFirst with get() = prev.IsNone
    member n.IsLast with get() = next.IsNone
    member n.Next = 
        System.Diagnostics.Trace.Assert(not n.IsLast)
        next.Value
    member n.Prev = 
        System.Diagnostics.Trace.Assert(not n.IsFirst)
        prev.Value

(You would still need to add some members to initialize or set the next/prev field - but these could be special construction functions such as CreateSingle, LinkBefore, LinkAfter etc. that help ensure the invariants your algorithms will need are maintained)

However these are, of course, simply design choices and you could just have well have used a record originally and done everything by hand from that point on.

1
2
3
4
type Node = 
    { name : string;
      mutable prev : Node option     
      mutable next : Node option  }

Kind regards

don

By on 9/15/2007 2:42 AM ()

Hi, I have another related question, I seem to be having issues using implicit construction on a class that inherits another class, the editor is telling me that my indentation is wrong. Is there some sort of limitation here or am I doing something wrong?

1
2
3
4
5
6
7
light#

type Window() = class
  inherit Form() as this
     let mutable aVariable =  0
     let mutable bVariable = 1 
  ...

This generates the error that the second "let" is not indented correctly, however, if I remove the inherit clause, the error goes away.

By on 9/15/2007 6:58 PM ()

Just align the "inherit" and the "let"

1
2
3
4
5
6
7
8
9
 

type Window() = 
     inherit Form() as this

     let mutable aVariable =  0
     let mutable bVariable = 1 

etc.

Kind regards

don

By on 9/16/2007 3:07 AM ()

Oh wow, I can't believe I missed that! So stupid! Alright, well this one is a little more challenging. I have searched through the expert F# samples, numerous ocaml tutorials and Rob's (excellent) wiki to no avail.

I wondering how or if I can do the following. 1.) Define a mutable value of some unknown type and 2.) define an abstract member with a getter/setter ie

1
2
3
4
5
light#
type sample() = class
  let mutable Result : 'a
  abstract member myResult with get() = Result and set(v) = Result <- v
  ...

In the first instance, it looks like F# wants me to initialize the value but how can this be done if one does not know the type? In the second, I have been presented with errors that tell me that the member is abstract but does not have a setter function however, I cannot figure out a syntax for writing an abstract one. As usual there are good reasons for doing all this, but the explanations are not worth wasting your time and page space on.

Thanks again
Matt

By on 9/16/2007 9:17 AM ()

Here are some options... hope this helps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 


type 'a sample =    
  val Result : 'a
  new(x:'a) = {Result = x}
  // ...


type 'a sample(x:'a) =
  let mutable Result = x
  member s.Result 
    with get()  = Result
    and set(v) = Result <- v

type 'a sample() = 
  abstract member Result : 'a with get, set

type 'a sample() =
  let mutable Result : 'a option = None
  abstract member Result : 'a with get, set
  default x.Result
    with get()  = if Result = None then failwith "" else Option.get Result
    and set(v) = Result <- Some v      
By on 9/16/2007 11:29 AM ()

Thanks Julien, I have already tried using Option types for my anonymous mutable declaration however, I get a strange error (or rather warning) when I do it. The following example:

1
2
3
4
#light 
type example = class
  let mutable result : 'a option = None
end

produces the warning that type 'a is less generic than the type annotations and has been constrained to type obj

Matt

By on 9/16/2007 6:13 PM ()

When you have such a declaration in your class, you need to define your class as generic

1
2
3
type ('a, 'b) example =
  let mutable result : 'a option  = None
  let mutable other_result : 'b option = None
By on 9/16/2007 11:34 PM ()

Hi Don,

Thanks also for your response. Before I say anything else, i might just comment on how great it is that you frequent these forums, especially stopping to give help to us newbies! Thanks also for your comments on classes, believe it or not, they were a real penny dropper for me. Things have just started to click in to place. The sample chapters of Expert F# do not mention those ideas of implicit class construcion, but they make far more sense. Thanks.

Matt

By on 9/15/2007 8:39 AM ()

F# doesn't allow null as a valid value for F# types since option types are generally used instead in F# code, if you want to assign null to an F# type then you'll need to cast the null to the correct type, for example...

1
2
3
4
5
6
7
8
#light

type node = class
    val mutable name : string
    val mutable next : node
    val mutable prev : node
    new(objName) = { name = objName; next = (null :> node); prev = (null :> node) } 
end
By on 9/14/2007 6:59 PM ()

Hi Julian,

Thanks for your reply. I'm not sure that "null" is the best way to go about it. But it was all that I could think of given y C++ heritage. I would prefer to use an option type, but i'm not sure how to do it, as the option and the class are mutually dependent. The option type would need to be

1
2
3
4
#light 
type Next =
 | NextObj of node
 | Nothing 

but the node class would need to know about the Next type before I could write it and vis-versa. Any hints on how I can do this?

The reason for the Nothing type is for construction and traversal at runtime.

Matt

By on 9/14/2007 10:51 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