Hi g.s.,

F# 1.1.12 supports signature files containing module types that are implicitly related to a single module implementation. Independent definitions of module types that can be applied to multiple module implementations are due to be implemented by the end of the year (though to be honest the implementation is simple enough that we may do it sooner since the topic has come up quite quickly for you.)

This means you currently have to duplicate PILA, e.g. use a signature file giving identical signatures for ImpPila and SemPila. The code is below.

One of the reasons we have not prioritorised this is that it turns out that many people prefer to present large portions of their APIs using the OO mechanisms of F# and .NET programming, and then use modules to hold "extra" functionality. Theses programmers would use the following signature:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 

exception Emptystack
exception Fullstack 

type 'a SemStack 
   with 
     static member Empty : int -> 'a SemStack
     member Push    : 'a  -> 'a SemStack
     member Pop     : unit -> 'a SemStack
     member Top     : 'a
     member IsEmpty : bool
     member Length  : int
   end

and an implementation such as the following (other implementations are also possible!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 

exception Emptystack
exception Fullstack 
type 'a SemStack = 
    | Empty of int
    | Push of 'a SemStack  * 'a 
    with
        static member Empty n : 'a SemStack = Empty(n) 
        member s.Max = 
           match s with 
           | Empty n -> n
           | Push(p,a) -> p.Max
        member s.Length = 
           match s with 
           | Empty n -> 0
           | Push(p,a) -> 1 + p.Length
        member s.Push a = 
           if s.Length = s.Max then raise Fullstack else Push(s,a) 
        member s.Pop() =
           match s with 
           | Push(p,a) -> p 
           | Empty n -> raise Emptystack
        member s.Top = 
           match s with 
           | Push(p,a) -> a 
           | Empty n -> raise Emptystack
        member s.IsEmpty = 
           match s with 
           | Push(p,a) -> false 
           | Empty n -> true
    end

Here is the approach using the duplicated signatures. The signature file (e.g. stack.fsi) would contain:

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

module SemPila : 
   sig
     type 'a stack
     val emptystack : int -> 'a stack
     val push : 'a  * 'a stack -> 'a stack
     val pop : 'a stack -> 'a stack
     val top : 'a stack -> 'a
     val empty : 'a stack -> bool
     val lungh : 'a stack -> int
     exception Emptystack
     exception Fullstack 
   end


module ImpPila : 
   sig
     type 'a stack
     val emptystack : int -> 'a stack
     val push : 'a  * 'a stack -> 'a stack
     val pop : 'a stack -> 'a stack
     val top : 'a stack -> 'a
     val empty : 'a stack -> bool
     val lungh : 'a stack -> int
     exception Emptystack
     exception Fullstack 
   end

and the implementation file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 

module SemPila =
  struct
    type 'a stack = Empty of int | Push of 'a stack  * 'a 
    exception Emptystack
    exception Fullstack 
    let emptystack n = Empty(n) 
    let rec max = function
        | Empty n -> n
        | Push(p,a) -> max p
    let rec lungh = function
        | Empty n -> 0
        | Push(p,a) -> 1 + lungh(p)
    let push (a, p) = if lungh(p) = max(p) then raise Fullstack else Push(p,a) 
    let pop = function
        | Push(p,a) -> p 
        | Empty n -> raise Emptystack
    let top = function
        | Push(p,a) -> a 
        | Empty n -> raise Emptystack
    let empty = function
        | Push(p,a) -> false 
        | Empty n -> true
  end

module ImpPila =
  struct
    type 'a stack = Pila of ('a array) * int 
    exception Emptystack
    exception Fullstack 
    let emptystack nm = Pila(Array.zero_create nm, -1)
    let push(x, Pila(s,n)) = if n = (Array.length(s) - 1) then raise Fullstack
                             else (Array.set s (n +1) x;  Pila(s, n +1))
    let top(Pila(s,n)) = if n = -1 then raise Emptystack 
                         else Array.get s n 
    let pop(Pila(s,n)) = if n = -1 then raise Emptystack
                         else Pila(s, n -1)
    let empty(Pila(s,n)) = if n = -1 then true else false 
    let lungh(Pila(s,n)) = n 
  end

Don

By on 10/22/2006 11:49 AM ()

BTW I have adjusted the implementation of the imperative stack to use Array.zero_create, which means you don't have to pass in the pesky "dummy" value.

Array.zero_create is a semi-safe function for use in exactly this kind of circumstance (i.e. building abstractions that use arrays under the hood but guarantee that any elements of the array that are actually accessed at runtime are first initialized). This function is "semi-safe" in that its incorrect use can lead to null pointer exceptions, since the array is initialized to an array of null values, but this doesn't lead to the possibility of true memory corruptions, which is Cardelli's definition of "type safety".

BTW do you think it's wise to give the imperative implementation a signature that makes it look as if its a functional implementation? Normally imperative implmentations are marked by using "unit" return types for many functions.

don

By on 10/22/2006 11:57 AM ()

very clear
really thanks a lot [:)]

By on 10/22/2006 4:28 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