Jack Fox
Jack Fox

Reputation: 945

difficulty returning moderately complex F# type signature

I've defined F# Tree and Stack types, with a pop member on the Stack. I can't get the type signature right on results of the pop. Here is my code up until I try to use pop:

type Tree<'a> =
    | Tree of 'a * 'a Tree * Tree<'a>
    | Node of 'a 
    | None

type 'a Stack =
    | EmptyStack 
    | Stack of 'a * 'a Stack 
    member x.pop = function
        | EmptyStack -> failwith "Empty stack"
        | Stack(hd, tl) -> (hd:'a), (tl:Stack<_>)

let myTree = Tree("A", Tree("B", Node("D"), None), Tree("C", Tree("E", None, Node("G")),  Tree("F", Node("H"), Node("J"))))

let myStack = Stack((myTree, 1), Stack.EmptyStack)

Now I've tried various ways to return the pop, and each one throws a different kind of error with the signature:

let (tree, level), z = myStack.pop

throws: stdin(22,24): error FS0001: This expression was expected to have type ('a * 'b) * 'c but here has type (Tree * int) Stack -> (Tree * int) * (Tree * int) Stack

//let (tree:Tree<_>, level:int), z:Stack<Tree<_>*int> = myStack.pop
let (tree:Tree<_>, level:int), z:Stack<'a> = myStack.pop
//let (tree:Tree<'a>, level:int), _ = myStack.pop
//let (tree:Tree<string>, level:int), z:Stack<Tree<string>*int> = myStack.pop

The attempt uncommented above throws: stdin(16,46): error FS0001: This expression was expected to have type (Tree<'b> * int) * 'c but here has type 'a Stack

Upvotes: 1

Views: 271

Answers (1)

Stephen Swensen
Stephen Swensen

Reputation: 22297

The problem is that pop here is an instance method taking one argument (due to function), but you want it to be an instance method taking zero arguments (i.e. unit), like

type 'a Stack =
    | EmptyStack 
    | Stack of 'a * 'a Stack 
    member x.pop() =
        match x with
        | EmptyStack -> failwith "Empty stack"
        | Stack(hd, tl) -> (hd:'a), (tl:Stack<_>)

and then call it like

let (tree,level), z = myStack.pop()

[Edit]

But actually, since Stack is immutable here, it doesn't really make sense to implement pop as an instance member, since then it's really more like peek. So you might want to implement it as a function in a companion module (or / and as a static member of Stack for compatibility with other .NET languages):

type 'a Stack = \\'
    | EmptyStack 
    | Stack of 'a * 'a Stack 

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Stack =
    let pop = function
        | EmptyStack -> failwith "Empty stack"
        | Stack(hd, tl) -> (hd:'a), (tl:Stack<_>)

and call it like

let (tree, level), z = Stack.pop myStack

Upvotes: 4

Related Questions