OCaml: how to create an inductive type with Set argument of same type - recursion

In OCaml I can define the following type:
type mytype = Base of int
| Branch of (int * (collection -> collection))
and collection = mytype list
Assuming I define a comparison function based on the int value of each constructor, how can I transform collection to be a Set instead of a list?

This is one of the cases where you will need to use recursive modules. In fact you can see that this is the actual example you get in the documentation of the feature. So something along these lines should do it:
module rec Mytype : sig
type t = Base ...
val compare : t -> t -> int
end = struct
type t = Base ...
let compare v0 v1 = ...
end
and Collection : Set.S with type elt = Mytype.t
= Set.Make (Mytype)

Related

Extend mutually recursive functors

I am writing a compiler and need to represent several structures that are co recursive and depend on the data-structure representing expressions. At the beginning of compilation my expressions are not typed but I do type them at a later stage.
I wrote the following functors to be able to reuse code during the process:
module type Exp = sig
type t
end
module type IR = sig
type exp
type ty =
| Unknown
| Typed of exp
type exp_descr =
| Leaf
| Node of exp
end
module MyIR (E: Exp) = struct
type ty =
| Unknown
| Typed of E.t
type exp_descr =
| Leaf
| Node of E.t
type exp = E.t
end
module UntypedExp (TD: IR) : (Exp with type t = TD.exp_descr) = struct
type t = TD.exp_descr
end
module TypedExp (TD: IR) : Exp = struct
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
module rec UTExp : Exp = UntypedExp(UTIR)
and UTIR : IR = MyIR(UTExp)
module rec TExp : Exp = TypedExp(TIR)
and TIR : IR = MyIR(TExp)
I now have 2 intermediate representations one that uses untyped expressions and the other that uses typed expressions.
I now want to write a printing module and I want to factorize code in the same manner as I did earlier. Below is my unsuccessful attempt, I don't understand how properly extend TExp and UTexp.
More specifically, I don't know how to share the field constructor defined in TypedExp.
module type ExpPrint = sig
type t
val string_of_t: t -> string
end
module type IRPrint = sig
include IR
val string_of_ty: ty -> string
val string_of_exp_descr: exp_descr -> string
val string_of_exp: exp -> string
end
module MyExpPrint (R: IR) (E: ExpPrint with type t = R.exp) : (IRPrint with type exp := R.exp and type exp_descr := R.exp_descr and type ty := R.ty) = struct
open R
let string_of_exp = E.string_of_t
let string_of_ty = function
| R.Unknown -> "Unknown"
| Typed e -> "Typed: " ^ string_of_exp e
let string_of_exp_descr = function
| R.Leaf -> "Leaf"
| Node e -> "Node: " ^ string_of_exp e
end
module UTExpPrint (E : module type of UTExp) (R: IRPrint with type exp = E.t) : (ExpPrint with type t := R.exp_descr) = struct
open E
let string_of_t = R.string_of_exp_descr
end
module TExpPrint (E : module type of TExp) (R: IRPrint with type exp = E.t) : (ExpPrint with type t := R.exp) = struct
open E
let string_of_t e = R.string_of_exp_descr e.TExp.descr ^ " " ^ R.string_of_ty e.ty
end
EDIT: fixes the problems with MyExpPrint
Since the module type Exp is defined as
module type Exp = sig type t end
any signature constraint of the form M: Exp makes M unusable since it hides all information about M, except the existence of an abstract type M.t. This abstract type is unusable since there are no functions between this type and the outside world.
For instance, this module definition defines a type and immediately hides it to the outside world:
module TypedExp (TD: IR) : Exp = struct
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
What you wanted was simply
module TypedExp (TD: IR) = struct
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
If you really want to add a signature constraint, the right one would be
module TypedExp (TD: IR): sig
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
= struct
type t =
{
ty : TD.ty;
descr : TD.exp_descr;
}
end
Note that that I did not use Exp with type t = ... for two reasons: First, the with constraint cannot define new types. Second, Exp with type t = ... is just a complicated way to write sig type t = ... end.
This is the core issue with your code: it is hiding all information that would make possible to manipulate meaningfully the type that you defines.
For instance, after removing the signature constraint on functor result, fixing the signature in the recursive module constraints, simplifying the signature of IRprint to
module type IRPrint = sig
type ty
type exp_descr
type exp
val string_of_ty: ty -> string
val string_of_exp_descr: exp_descr -> string
val string_of_exp: exp -> string
end
then the functor TExpPrint can be fixed with
module TExpPrint
(E : module type of TExp)
(R: IRPrint with type exp_descr = TIR.exp_descr
and type exp = E.t
and type ty = TIR.ty)
=
struct
open E
let string_of_t e =
R.string_of_exp_descr e.E.descr ^ " " ^ R.string_of_ty e.ty
end
and I expect the rest of the errors to follow since it becomes possible to share the right type equalities.

What is the difference between int -> int -> int and (int*int) -> int in SML?

I have noticed that there are 2 ways of defining functions in SML. For example if you take the add function, these are the two ways:
fun add x y = x+y;
fun add(x,y) = x+y;
The first method creates the function type as:
val add = fn : int -> int -> int
The second one creates the function type as:
val add = fn : int * int -> int
What is the difference between these two types for the same function? And also why are there two types for the same function?
If we remove the syntactic sugar from your two definitions they become:
val add = fn x => fn y => x+y
and
val add = fn xy =>
case xy of
(x,y) => x+y
So in the first case add is a function that takes an argument x and returns another function, which takes an argument y and then returns x+y. This technique of simulating multiple arguments by returning another function is known as currying.
In the second case add is a function that takes a tuple as an argument and then adds the two elements of the tuple.
This also explains the two different types. -> is the function arrow, which associates to the right, meaning int -> int -> int is the same as int -> (int -> int) describing a function that takes an int and returns an int -> int function.
* on the other hand is the syntax used for tuple types, that is int * int is the type of tuples containing two ints, so int * int -> int (which is parenthesized as (int * int) -> int because * has higher precedence than ->) describes a function that takes a tuple of two ints and returns an int.
The reason those 2 functions are different is because of the phenomenon of Currying. Specifically, Currying is the ability to write any function with dom(f) = R^{n} as a function that takes inputs from R n-times. This basically is accomplished by ensuring that each input returns a function for the next variable to take in. This is what the -> sign represents - It's a fundamental result from the Curry-Howard Isomorphism. So :
fun addCurry x y = x + y (* int -> int -> int *)
fun addProd (x,y) = x + y (* (int*int) -> int *)
tells us that addCurry is the reduction of addProd into a form that can be used to "substitute" and return variables. So, addProd and addCurry are Contextually-Equivalent. However, they are not Semantically-Equivalent.
(int*int) is a product-type. It says that it expects input1=int and input2=int. int -> int says that it takes an int and returns an int. It's an arrow-type.
If you're interested, you may also want to know that there are only 2 kinds of arguments to SML functions :
1) Curried
2) Tuples - So, fun addProd (x,y) represents (x,y) as a tuple to the function argument.

F# Type Provider Referencing Custom Types

I'm constructing a simple type provider, but I seem to be running into problems when referencing types I created. For instance, given
namespace Adder
type Summation = Summation of int
module QuickAdd =
let add x y = x + y |> Summation
I want to make the following test case pass:
module Adder.Tests
open Adder
open NUnit.Framework
type Simple = QuickAddProvider<1, 2>
[<Test>]
let ``Simple sample is 3`` () =
let foo = Simple()
Assert.AreEqual(foo.Sample, Summation 3)
With the following type provider:
namespace Adder
open Microsoft.FSharp.Core.CompilerServices
open ProviderImplementation.ProvidedTypes
open System.Reflection
[<TypeProvider>]
type public QuickAddProvider (config : TypeProviderConfig) as this =
inherit TypeProviderForNamespaces ()
let ns = "Adder"
let asm = Assembly.GetExecutingAssembly()
let paraProvTy = ProvidedTypeDefinition(asm, ns, "QuickAddProvider", Some typeof<obj>)
let buildTypes (typeName:string) (args:obj[]) =
let num1 = args.[0] :?> int
let num2 = args.[1] :?> int
let tpType = ProvidedTypeDefinition(asm, ns, typeName, Some typeof<obj>)
let result = QuickAdd.add num1 num2
let orig = ProvidedProperty("Sample", typeof<Summation>, GetterCode = (fun args -> <## result ##>))
tpType.AddMember(orig)
tpType.AddMember(ProvidedConstructor([], InvokeCode = (fun args -> <## () ##>)))
tpType
let parameters =
[ProvidedStaticParameter("Num1", typeof<int>)
ProvidedStaticParameter("Num2", typeof<int>)]
do paraProvTy.DefineStaticParameters(parameters, buildTypes)
do this.AddNamespace(ns, [paraProvTy])
[<TypeProviderAssembly>]
do()
I run into unexpected errors in the test file:
The type provider 'Adder.QuickAddProvider' reported an error in the context of provided type 'Adder.QuickAddProvider,Num1="1",Num2="2"', member 'get_Sample'. The error: Unsupported constant type 'Adder.Summation'
With the following errors in the generated file:
The type "Summation" is not defined
The namespace or module "Adder" is not defined
The test case compiles and passes when replacing the Summation type with int, so I know my type provider isn't terribly wrong. Do I need to somehow "import" the Summation type somewhere?
This error usually means that you are creating a quotation that contains a value of custom type. The quotations in type providers can only contain values of primitive types - the compiler knows how to serialize these - but it cannot handle custom types.
In the snippet, this happens here:
let result = QuickAdd.add num1 num2
let orig = ProvidedProperty("Sample", typeof<Summation>, GetterCode = (fun args ->
<## result ##>))
Here, the GetterCode returns a quotation containing value of type Summation which is not supported. To make this work, you can do various things - generally, you'll need to come up with some other quoted expression that produces the value you want.
One option is to do the calculation inside the quotation rather than outside:
<## QuickAdd.add num1 num2 ##>
The other option would be to re-create the Summation value in the quotation:
let (Summation n) = result
<## Summation n ##>
This works, because it only needs to serialize a primitive int value and then generate a call to the Summation case constructor.

Hashtable of mutable variable in Ocaml

I need to use hashtable of mutable variable in Ocaml, but it doesn't work out.
let link = Hashtbl.create 3;;
let a = ref [1;2];;
let b = ref [3;4];;
Hashtbl.add link a b;;
# Hashtbl.mem link a;;
- : bool = true
# a := 5::!a;;
- : unit = ()
# Hashtbl.mem link a;;
- : bool = false
Is there any way to make it works?
You can use the functorial interface, which lets you supply your own hash and equality functions. Then you write functions that are based only on the non-mutable parts of your values. In this example, there are no non-mutable parts. So, it's not especially clear what you're expecting to find in the table. But in a more realistic example (in my experience) there are non-mutable parts that you can use.
If there aren't any non-mutable parts, you can add them specifically for use in hashing. You could add an arbitrary unique integer to each value, for example.
It's also possible to do hashing based on physical equality (==), which has a reasonable definition for references (and other mutable values). You have to be careful with it, though, as physical equality is a little tricky. For example, you can't use the physical address of a value as your hash key--an address can change at any time due to garbage collection.
Mutable variables that may happen to have the same content can still be distinguished because they are stored at different locations in memory. They can be compared with the physical equality operator (==). However, OCaml doesn't provide anything better than equality, it doesn't provide a nontrivial hash function or order on references, so the only data structure you can build to store references is an association list of some form, with $\Theta(n)$ access time for most uses.
(You can actually get at the underlying pointer if you play dirty. But the pointer can move under your feet. There is a way to make use of it nonetheless, but if you need to ask, you shouldn't use it. And you aren't desperate enough for that anyway.)
It would be easy to compare references if two distinct references had a distinct content. So make it so! Add a unique identifier to your references. Keep a global counter, increment it by 1 each time you create a reference, and store the counter value with the data. Now your references can be indexed by their counter value.
let counter = ref 0
let new_var x = incr counter; ref (!counter, x)
let var_value v = snd !v
let update_var v x = v := (fst !v, x)
let hash_var v = Hashtbl.hash (fst !v)
For better type safety and improved efficiency, define a data structure containing a counter value and an item.
let counter = ref 0
type counter = int
type 'a variable = {
key : counter;
mutable data : 'a;
}
let new_var x = incr counter; {key = !counter; data = x}
let hash_var v = Hashtbl.hash v.key
You can put the code above in a module and make the counter type abstract. Also, you can define a hash table module using the Hashtbl functorial interface. Here's another way to define variables and a hash table structure on them with a cleaner, more modular structure.
module Counter = (struct
type t = int
let counter = ref 0
let next () = incr counter; !counter
let value c = c
end : sig
type t
val next : unit -> t
val value : t -> int
end)
module Variable = struct
type 'a variable = {
mutable data : 'a;
key : Counter.t;
}
let make x = {key = Counter.next(); data = x}
let update v x = v.data <- x
let get v = v.data
let equal v1 v2 = v1 == v2
let hash v = Counter.value v.key
let compare v1 v2 = Counter.value v2.key - Counter.value v1.key
end
module Make = functor(A : sig type t end) -> struct
module M = struct
type t = A.t Variable.variable
include Variable
end
module Hashtbl = Hashtbl.Make(M)
module Set = Set.Make(M)
module Map = Map.Make(M)
end
We need the intermediate module Variable because the type variable is parametric and the standard library data structure functors (Hashtbl.Make, Set.Make, Map.Make) are only defined for type constructors with no argument. Here's an interface that exposes both the polymorphic interface (with the associated functions, but no data structures) and a functor to build any number of monomorphic instances, with an associated hash table (and set, and map) type.
module Variable : sig
type 'a variable
val make : 'a -> 'a variable
val update : 'a variable -> 'a -> unit
val get : 'a variable -> 'a
val equal : 'a -> 'a -> bool
val hash : 'a variable -> int
val compare : 'a variable -> 'b variable -> int
end
module Make : functor(A : sig type t end) -> sig
module M : sig
type t = A.t variable.variable
val make : A.t -> t
val update : t -> A.t -> unit
val get : t -> A.t
val equal : t -> t -> bool
val hash : t -> int
val compare : t -> t -> int
end
module Hashtbl : Hashtbl.S with type key = M.t
module Set : Set.S with type key = M.t
module Map : Map.S with type key = M.t
end
Note that if you expect that your program may generate more than 2^30 variables during a run, an int won't cut it. You need two int values to make a 2^60-bit value, or an Int64.t.
Note that if your program is multithreaded, you need a lock around the counter, to make the incrementation and lookup atomic.

Functors in OCaml

I am having a bit of a problem with a functor (and it's resultant type). Below, I have a Set functor that uses an Ordered type. I actually used the set.ml that comes with OCaml for some guidance, but I seem to be doing everything ahem right. I created an Ordered module with integers and applied it to the Set functor to get the last module on this code sample, IntSet.
The next line fails, when I try to insert an integer. I get the following type error:
Error: This expression has type int but is here used with type
SetInt.elt = Set(OrdInt).elt
Don't get me wrong, the type system is correct here. The top level reports that the type of the SetInt.elt is Set(OrdInt).elt, but when I do the same operations to set up a Set using the one provided by OCaml the 'same' line is, SetInt.elt = OrderedInt.t. Seems like I should be getting SetInt.elt = Ordered.t.
This is so simple, I'm probably just missing some stupid detail! argh!
Please Note: I have simplified the member/insert functions here since this issue has to do with types.
module type Ordered =
sig
type t
val lt : t -> t -> bool
val eq : t -> t -> bool
val leq : t -> t -> bool
end
module type S =
sig
type elt
type t
exception Already_Exists
val empty : t
val insert : elt -> t -> t
val member : elt -> t -> bool
end
module Set (Elt:Ordered) : S =
struct
type elt = Elt.t
type t = Leaf | Node of t * elt * t
exception Already_Exists
let empty = Leaf
let insert e t = t
let member e t = false
end
module OrdInt : Ordered =
struct
type t = int
let lt a b = a < b
let eq a b = a = b
let leq a b = a <= b
end
module IntSet = Set (OrdInt)
(* line that fails *)
let one_elm = IntSet.insert 1 IntSet.empty
You need to change these two lines
module Set (Elt:Ordered) : S =
module OrdInt : Ordered =
to
module Set (Elt:Ordered) : S with type elt = Elt.t =
module OrdInt : Ordered with type t = int =
Without these, the modules will not have signatures that expose the types elt and t as int.
[Edit]:
The set.ml doesn't have the 'with' bit, because there's a sml.mli, which declares the signature for the functor and it does have the 'with'. Also, OrdInt doesn't need 'with' if you don't explicitly specify a signature for it, like this:
module OrdInt =
You can also construct the set by defining the module in place:
module IntSet = Set (struct
type t = int
let lt a b = a < b
let eq a b = a = b
let leq a b = a <= b
end)

Resources