0

i am new to this language. In order to try and understand referencing i have tried implementing a simple directed list the freshman college computer science way.

type item = { 
    value:float 
    next:ref<item>
}

type list() = 
    let head:ref<item> = null // tried instantiation so many different ways and it likes none of em

    let sum i = 
        if i == null then
            0
        else 
            i.value + sum i.next // constructor not defined?

Please tell me why im bad at this

vlad
  • 4,748
  • 2
  • 30
  • 36

1 Answers1

5

First of all you try to implement it in some imperative way - this is ok, but not really functional. Anyway, the first thing you have problems with is, that you cannot assign null - if you really want to you have to add [<AllowNullLiteral>] to your item type (but of course you have to make it a class instead of a record):

[<AllowNullLiteral>]
type Item(value, next) = 
    member this.value = value
    member this.next : Item ref = next

let head : ref<Item> = ref null

let rec sum (i : Item) = 
    if i = null then
        0.0
    else 
        i.value + sum !i.next

But this is almost never a good idea, so I would start like this:

module List =

   type Item = { value : float; next : List }
   and  List = Item option ref

   let empty : List = ref None
   let single x = { value = x; next = ref None }

   // this is how you can change the list
   let rec append x l =
      let item = single x
      match !l with
      | None -> 
         l := Some item
      | Some node ->
         append x node.next

   let rec sum (l : List) =
      match !l with
      | None      -> 0.0
      | Some item -> item.value + sum item.next

now if you watch closely you will see that you don't really need the refs if you just append at the front and voila ... you got your usual functional list ;)

PS: you forgot some other things too:

  • you are using floats in there so you have to use 0.0 instead of 0
  • your sum-function has to be recursive (mind you it's not tail-recursive so you will get problems with big lists!)
  • you have to dereference ref-cells with !
  • you have to construct ref-cells with ref (for example ref null)
  • your type list() = made no sense to me so I converted it into a module

PPS: please not that it's not the F#-Way to mutate things like this - it's just to show you how you can do it ... but don't if you don't have to

Simon Lomax
  • 8,714
  • 8
  • 42
  • 75
Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • I appreciate your answer, but as stated in the question I implemented the code as such to get a grasp on referencing and instanciation. Either I just dont understand your code or it doesnt really answer what i was after? Sorry you changed the code so much it seems a bit like latin to me right now ^^ – user3797085 Jul 23 '14 at 08:36
  • where exactly is the problem? I changed the first code-fragment only so much as to get you compiling code - for example, you cannot implement `Item` as a record because F# will allow no `null`-literal for those (ok I did Uppercase the class-name too - *types* should be upper-case ;) ) – Random Dev Jul 23 '14 at 08:46
  • the second one is just the typical solution to the `null`-problem (use Options) and I made the types a bit more readable and cleaner - just ask what you don't understand and I will explain – Random Dev Jul 23 '14 at 08:48
  • It's a great answer, but I can't understand why you used 'ref' instead of 'option'. Could you explain this point? – FoggyFinder Mar 06 '16 at 21:46
  • @FoggyFinder because I wanted to stay close to the question and in a imperative(mutable) linked-list you usually want to change the pointers to the next list element from time to time (as I said not really necessary here) - and the `ref cell` allows that (it's mutable, you can reset it with `listItem.next := Some otherNode` – Random Dev Mar 06 '17 at 05:17