0

I am trying to extend the existing int library to a new library called "bigint". I am keeping the type of the datatype bigint as int list. Basically, I want a function (lets call it getbigint)which accepts any int and store each of its digits in a separate cell of int list and then return this int list. So if I enter:

getbigint 9

it should give me:

val it =[9]:bigint 

How can I achieve this? For the time being, I assume that input to this function is single digit int only. Here is what I have done till now:

signature BigInt =
    sig
        type bigint = int list
        val getbigint: int -> bigint
    end;

structure struct_bigint : BigInt = 
    struct
        fun getbigint (i:int) = 
            let
              val h = [i]:bigint
            in h
            end
    end
(*val j = getbigint 9;*)

which is giving error.

sshine
  • 15,635
  • 1
  • 41
  • 66
Ankit Shubham
  • 2,989
  • 2
  • 36
  • 61

1 Answers1

1

A signature implements nothing. It describes what a structure looks like to the outside world. Think of it as a specification. A structure that matches it must provide implementations of the elements in the signature. Note that when you run your code you get the following error:

Error: unmatched type specification: bigint

SML detects that you have something in a signature that isn't matched by a corresponding implementation in the structure.

A minimal fix would simply be to add the line

type bigint = int list

in the structure definition before the implementation of fun getbigint. This would allow the line

val j = struct_bigint.getbigint 9;

to work. But -- it might seem a bit silly to have the line

type bigint = int list

twice -- once in the signature and once in the structure. And, in some ways, it is silly.

Implementation details don't really belong in the signature. It would make more sense to just have type bigint in the signature and the implementation in terms of int list in the structure. This would allow you to later on change your mind about implementation (say you want to use arrays rather than lists) in such a way that code which uses the structure is completely unaffected. Something like:

signature BIGINT =
    sig
        type bigint
        val getbigint: int -> bigint
    end

structure BigInt : BIGINT = 
    struct
        type bigint = int list

        fun getbigint (i:int): bigint = [i];            
    end;

I cleaned up your implementation of getbigint since the let binding in it seemed a bit pointless, and chose something more idiomatic for names of the signature (all upper case) and structure (camel case with leading capital).

Finally, note that getbigint 9 won't work out of the box. You can do one of three things:

1) Explicitly use the qualified name: BigInt.getbigint 9

2) Use the line val getbigint = BigInt.getbigint to give the name getbigint its intended meaning in the current scope

3) Use the line open BigInt to move the structure's definitions to the top-level, after which getbigint 9 will work as expected.

When I started programming in SML, I used to open a lot of structures (Char, `List etc.). If you do this thoughtlessly, sooner or later you run into bugs where opening a structure introduces a name clash. For that reason, I now almost always use approach 1) or 2).

John Coleman
  • 51,337
  • 7
  • 54
  • 119