How can one specify the value type for an OCaml map - module

I want to declare ahead of time the value type for a map type.
The functor Map.Make returns a Map.S with two type definitions:
type key
type !+'a t
Type 'a appears to be the type of values in the map. For example, this is the function for adding a key (of type key and value of type 'a:
val add: key -> 'a -> 'a t -> 'a t
One can write the key type like this:
module type M = Map.S with type key = string
But I couldn't figure out how to specify the value type. This isn't valid syntax:
module type M = Map.S with type key = string and 'a = int

One way to look at this is that you're trying to impose monomorphism in the wrong place. The essence of Map.S is that it's polymorphic in the element type.
You can easily define a type for maps from string keys to int values:
# module M = Map.Make(String);;
. . .
# type string_int_mod = int M.t;;
type string_int_mod = int M.t
# let f (m: string_int_mod) s i = M.add s i m;;
val f : string_int_mod -> M.key -> int -> int M.t = <fun>
In many cases, the polymorphism inferred by OCaml is clearer than specifically ascribed types. At least in my opinion. The types inferred by OCaml tell you what the code is really doing and where it has degrees of freedom.

Related

Is there any use case for an anonymous OCaml structure

The OCaml manual, Chapter 2, says
a structure and is introduced by the struct…end construct, which contains an arbitrary sequence of definitions. The structure is usually given a name with the module binding.
Is there any use case for the creating a struct and not giving it a module name.
If not, then we always use
module Name =
struct
...
end
and so the struct keyword seems a bit redundant.
It's possible and even common (in my code at least) to use nameless structures. One example:
module MyStrSet =
Set.Make(struct type t = string let compare a b = compare b a end)
To expand slightly on Jeffrey's answer, an OCaml functor maps a module to another module. It doesn't care about the module's name.
Consider the following trivial example.
module type SIG =
sig
val x : int
end
module A (B : SIG) =
struct
let y = B.x * 2
end
I've defined a functor A which takes a module B that fulfills the module type SIG. Now, I could define a module Twenty_one that supplies an x value of 21, and then give that to the functor A to create module C.
module Twenty_one =
struct
let x = 21
end
module C = A (Twenty_one)
Or I could directly use an anonymous structure.
module C = A (struct let x = 21 end)
We don't even need to name SIG.
module A (B : sig val x : int end) =
struct
let y = B.x * 2
end
module C = A (struct let x = 21 end)
Strongly into opinion territory, but you may want to give these things names in your code, if it aids with reuse and expressivess.
E.g.
module Int =
struct
type t = int
let compare = compare
end
module Int_map = Map.Make (Int)
Vs.
module Int_map = Map.Make (struct type t = int let compare = compare end)
Another thing you can do with an anonymous structure, that's more relevant to recent (as of 4.08.0) OCaml, is the ability to use open with it, for a syntactically-cheap way to hide names in your namespace (until you write an interface file anyway):
open struct
type hidden_type = string
let hidden_name = 42
end
This feature is called generalized-open, and the relevant manual page for it is here.

OCaml User-Defined Type and Function Return Error

I was writing a function with user-defined types in OCaml when I encountered an error message that I don't understand.
I'm currently using the OCaml interactive toplevel and also Visual Studio Code to write my code. The strange thing is that when I run the code in Visual Studio Code, it compiles fine but encounters the error in the interactive toplevel.
The OCaml code that I am referring to is as follows:
type loc = int;;
type id = string;;
type value =
| Num of int
| Bool of bool
| Unit
| Record of (id -> loc)
;;
type memory = (loc * value) list;;
exception NotInMemory;;
let rec memory_lookup : (memory * loc) -> value
= fun (mem, l) ->
match mem with
| [] -> raise NotInMemory
| hd :: tl -> (match hd with
| (x, a) -> if x = l then a else (memory_lookup (tl, l))
)
;;
The code that I wrote is basically my rudimentary attempt at implementing/emulating looking up memory and returning corresponding values.
Here's an example input:
memory1 = [ (1, Num 1) ; (2, Bool true) ; (3, Unit) ];;
Here's the expected output:
memory_lookup (memory1, 2);;
- : value = Bool true
However, here's the actual output:
Characters: 179-180:
| (x, a) -> if x = l then "a" else (memory_lookup (tl, l)))
Error: This expression has type value/1076
but an expression was expected of type value/1104
(Just for clarification: the error is regarding character a)
Does anybody know what type value/1076 and type value/1104 mean? Also, if there is anything wrong with the code that I wrote, would anybody be kind enough to point it out?
Thank you.
This kind of error happens in the toplevel when a type is defined multiple times, and some values of the old type are left in scope. A simple example is
type t = A
let x = A;;
type t = A
let y = A;;
x = y;;
Error: This expression has type t/1012 but an expression was expected of type
t/1009
The numerical part after the type name in value/1076 is a binding time for the type value. This binding time is used as a last resort to differentiate between two different types that happens to have the same name. Thus
Error: This expression has type value/1076
but an expression was expected of type value/1104
means that the value memory1 was defined with a type value defined at time 1076, whereas the function memory_lookup expected values of the type value defined at a later date (aka at time 1104). The binding times are a bit arbitrary , so they may be replaced by simply value/1 and value/2 in OCaml 4.08 .

Return tuple of lists from function

I'd like to write a function that returns two lists in Elm but I'm running into issues. It seems like the compiler cannot match the types of the empty list [].
import Html exposing (text)
main =
let
(a, b) = genList
in
text "Hello"
genList: List Float List Float
genList =
([], [])
The compiler errors are as follows:
Detected errors in 1 module.
-- TYPE MISMATCH ---------------------------------------------------------------
`genList` is being used in an unexpected way.
6| (a, b) = genList
^^^^^^^
Based on its definition, `genList` has this type:
List Float List Float
But you are trying to use it as:
( a, b )
-- TYPE MISMATCH ---------------------------------------------------------------
The definition of `genList` does not match its type annotation.
11| genList: List Float List Float
12| genList =
13| ([], [])
The type annotation for `genList` says it is a:
List Float List Float
But the definition (shown above) is a:
( List a, List b )
I haven't found any way of giving a type hint for the empty list. Checking the documentation, it doesn't go that deep:
https://guide.elm-lang.org/core_language.html
http://elm-lang.org/docs/syntax#functions
The type signature also needs the (.., ..) tuple syntax like:
genList: (List Float, List Float)
genList =
([], [])
[] is the correct syntax for generating an empty list though. If you want to know more about the List type, it's probably better to look at the docs on package.elm-lang.org. The two links you shared are more "intro guides" than comprehensive docs.

What does comparable mean in Elm?

I'm having trouble understanding what exactly a comparable is in Elm. Elm seems as confused as I am.
On the REPL:
> f1 = (<)
<function> : comparable -> comparable -> Bool
So f1 accepts comparables.
> "a"
"a" : String
> f1 "a" "b"
True : Bool
So it seems String is comparable.
> f2 = (<) 1
<function> : comparable -> Bool
So f2 accepts a comparable.
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
comparable
String
So String is and is not comparable?
Why is the type of f2 not number -> Bool? What other comparables can f2 accept?
Normally when you see a type variable in a type in Elm, this variable is unconstrained. When you then supply something of a specific type, the variable gets replaced by that specific type:
-- says you have a function:
foo : a -> a -> a -> Int
-- then once you give an value with an actual type to foo, all occurences of `a` are replaced by that type:
value : Float
foo value : Float -> Float -> Int
comparable is a type variable with a built-in special meaning. That meaning is that it will only match against "comparable" types, like Int, String and a few others. But otherwise it should behave the same. So I think there is a little bug in the type system, given that you get:
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
comparable
String
If the bug weren't there, you would get:
> f2 "a"
As I infer the type of values flowing through your program, I see a conflict
between these two types:
Int
String
EDIT: I opened an issue for this bug
Compare any two comparable values. Comparable values include String, Char, Int, Float, Time, or a list or tuple containing comparable values. These are also the only values that work as Dict keys or Set members.
taken from the elm docs here.
In older Elm versions:
Comparable types includes numbers, characters, strings,~~
lists of comparable things, and tuples of comparable things. Note that
tuples with 7 or more elements are not comparable; why are your tuples
so big?
This means that:
[(1,"string"), (2, "another string")] : List (Int, String) -- is comparable
But having
(1, "string", True)` : (Int, String, Bool) -- or...
[(1,True), (2, False)] : List (Int, Bool ) -- are ***not comparable yet***.
This issue is discussed here
Note: Usually people encounter problems with the comparable type when they try to use a union type as a Key in a Dict.
Tags and Constructors of union types are not comparable. So the following doesn't even compile.
type SomeUnion = One | Two | Three
Dict.fromList [ (One, "one related"), (Two, "two related") ] : Dict SomeUnion String
Usually when you try to do this, there is a better approach to your data structure. But until this gets decided - an AllDict can be used.
I think this question can be related to this one. Int and String are both comparable in the sense that strings can be compared to strings and ints can be compared to ints. A function that can take any two comparables would have a signature comparable -> comparable -> ... but within any one evaluation of the function both of the comparables must be of the same type.
I believe the reason f2 is confusing above is that 1 is a number instead of a concrete type (which seems to stop the compiler from recognizing that the comparable must be of a certain type, probably should be fixed). If you were to do:
i = 4 // 2
f1 = (<) i -- type Int -> Bool
f2 = (<) "a" -- type String -> Bool
you would see it actually does collapse comparable to the correct type when it can.

OCaml: Tree functions

Are there any modules or functions for dealing with trees? I have a type that looks like this:
type t =
Leaf of string (* todo: replace with 'a *)
| Node of string * t list
I'm struggling to do insertion, removal of subtrees, etc.
I've used Google but can't find anything.
Read the implementation of module Set in the sources of the OCaml standard library.
They are implemented with binary trees, only a little more sophisticated than yours.
(I would recommend you start with binary trees instead of having a list of children as you seem to have defined)
In the past, I've used ocamlgraph.
This is not a trivial lib to use, but if you need to insert nodes and change path, that could the trick, I've never used that in a b-tree context though...
And extracted from the language documentation:
The most common usage of variant types
is to describe recursive data
structures. Consider for example the
type of binary trees:
#type 'a btree = Empty | Node of 'a * 'a btree * 'a btree;;
type 'a btree = Empty | Node of 'a * 'a btree * 'a btree
This definition reads as follow: a
binary tree containing values of type
'a (an arbitrary type) is either
empty, or is a node containing one
value of type 'a and two subtrees
containing also values of type 'a,
that is, two 'a btree.
Operations on binary trees are
naturally expressed as recursive
functions following the same structure
as the type definition itself. For
instance, here are functions
performing lookup and insertion in
ordered binary trees (elements
increase from left to right):
#let rec member x btree =
match btree with
Empty -> false
| Node(y, left, right) ->
if x = y then true else
if x < y then member x left else member x right;;
val member : 'a -> 'a btree -> bool = <fun>
#let rec insert x btree =
match btree with
Empty -> Node(x, Empty, Empty)
| Node(y, left, right) ->
if x <= y then Node(y, insert x left, right)
else Node(y, left, insert x right);;
val insert : 'a -> 'a btree -> 'a btree = <fun>
Hope this helps