OCaml User-Defined Type and Function Return Error - error-handling

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 .

Related

Getting the name of a function in a macro

I wrote a macro to make code cleaner and clearer by using error message templates stored in a dict. In this example it inserts name of the function, see discourse and #__FUNCTION__, that throws the error.
exception = Dict(:foo => ("bar ~", ArgumentError))
macro ⛔(id)
msg, type = exception[id]
quote
msg = replace($msg, "~" => StackTraces.stacktrace()[1].func)
throw($type(msg))
end
end
This works fine in f that uses positional arguments,
f(x, p) = p < 5 ? x : #⛔ foo
f(1, 10)
#> ERROR: ArgumentError: bar f
but displays #..# when a keyword argument is used.
g(x; p = 3) = p < 5 ? x : #⛔ foo
g(1, p = 10)
#> ERROR: ArgumentError: bar #g#N
Here N is the nth expression evaluated in the session. Redefining g with the same syntax increments this number.
I am stuck after I couldn't spot a difference between the code produced by #⛔.
#macroexpand function f(x, p) p < 5 ? x : #⛔ foo end
#macroexpand function g(x; p = 3) p < 5 ? x : #⛔ foo end
Question
What is happening in g that is different from f?
That is the name of the method the expanded code is called in -- definitions with keyword arguments are lowered to dispatch helper methods called "keyword sorters": https://docs.julialang.org/en/v1/devdocs/functions/#Keyword-arguments. These make keywords arguments use dispatch (internally) and compilation just as other functions, instead of just dictionary lookup as e.g. in Python.
I don't think you can do what you want easily in that case, as the conversion process always happens. Taking a previous stack frame would work, but then you have to know whether you are within a keyword method beforehand.
Maybe the following approach works: pattern match the method name (#<f>#<N>), and then check whether it is an actual kwsorter method of any method of f. If so, proceed with f.

How do you define a non-generic recursive datatype in Idris?

This is literally my first line of Idris code. When I looked up the documentation, all appeared proper:
Idris> data T = Foo Bool | Bar (T -> T)
(input):1:6:
|
1 | data T = Foo Bool | Bar (T -> T)
| ^
unexpected reserved data
expecting dependent type signature
This makes me think I may need to declare T to be a symbol in some fashion?
It works as expected inside an Idris source file. At the REPL however, declarations need to be prefixed with the :let command:
:let data T = Foo Bool | Bar (T -> T)
Thanks for the question. I learned something trying to answer it.

Elm Maybe.withDefault

I need to unwrap a Maybe -value in one of my update functions:
update msg model =
case msg of
UpdateMainContent val ->
Maybe.withDefault 100 (Just 42)
model
This of course is dummy code and the
Maybe.withDefault 100 (Just 42)
is taken straight out of the documentation for Maybe and not supposed to actually do anything. The compiler is complaining and saying:
Detected errors in 1 module.
-- TYPE MISMATCH ----------------------------------- ./src/Review/Form/State.elm
The 1st argument to function `withDefault` is causing a mismatch.
15|> Maybe.withDefault 100 (Just 42))
16| -- Maybe.withDefault 100 (model.activeItem)
17| model
Function `withDefault` is expecting the 1st argument to be:
a -> b
But it is:
number
Why is it saying that "withDefault" is expecting the first argument to be
a -> b
when it is defined as
a -> Maybe a -> a
in the documentation?
You accidentally left in model:
UpdateMainContent val ->
Maybe.withDefault 100 (Just 42)
model -- <-- here
This makes the type inference algorithm think that Maybe.withDefault 100 (Just 42) should evaluate to a function that can take this model argument. For that to make sense, it expects 100 and 42 to be functions, but they aren't, and so it tells you.
It might help to see an example where this works:
f : Int -> Int
f x = x + 1
Maybe.withDefault identity (Just f) 0
This will evaluate to 1.

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.

Syntax errors in sml: Inserting LOCAL

The following method determines how many numbers can be added up starting from the beginning of the list without adding up to 4:
number_before_Reaching_sum (4, [1,2,3,4,6]);
should return : val it = 2 : int
fun number_before_reaching_sum (sum : int * int list) =
let val len_orig_list = length (#2 sum)
in fun num_bef_reach_sum (sum) =
if #1 sum <= 0
then len_orig_list - (length (#2 sum)) - 1
else num_bef_reach_sum (#1 sum - hd (#2 sum), tl (#2 sum))
end
syntax error: inserting LOCAL
syntax error found at EOF
I can't seem to find the errors in this code. I have some experience with Python, but just starting to learn sml. I'm loving it, but I don't understand all the error messages. I have really spent hours on this, but I think I don't know enough to solve my problem. I tried exchanging let with local, but i still got a syntax error (equalop). I think that the function between in and end is an expression and not a declaration. But I would appreciate any comments on this. If you come up with alternative code, it would be great if you did it without using more advanced features, since I'm just trying to get the basics down :-)
You probably meant this:
fun number_before_reaching_sum (sum : int * int list) =
let
val len_orig_list = length (#2 sum)
fun num_bef_reach_sum (sum) =
if #1 sum <= 0
then len_orig_list - (length (#2 sum)) - 1
else num_bef_reach_sum (#1 sum - hd (#2 sum), tl (#2 sum))
in
num_bef_reach_sum (sum)
end
With let … in … end, the part between let and in is for the local definitions; the part between in and end is for the expression which will be the evaluation of the let … in … end expression (this construct is indeed an expression).
Think of let … in … end as a possibly complex expression. You hoist parts of the expression as definitions, then rewrite the complex expression using references to these definitions. This help write shorter expressions by folding some of its sub‑expressions. This construct is also required when recursion is needed (a recursion requires a defining name).
Another way to understand it, is as the application of an anonymous function whose arguments bindings are these definitions.
Ex.
let
val x = 1
val y = 2
in
x + y
end
is the same as writing
(fn (x, y) => x + y) (1, 2)
which is the same as writing
1 + 2
You erroneously put a definition at the place of the expression the whole evaluates to.
(note I did not check the function's logic, as the question was about syntax)