the reasons of errors in ML code - sml

The below code is just a kind of prototype. What I want to know is why it fails to compile.
fun test(list) =
let
fun inner(list) =
let
val from = #1(hd(list))
in
if null(tl(list)) = false then innerinner(tl(list),from)
else false
end
fun innerinner(list,from) =
if #2(hd(list)) = from then true
else if null(list) = false then innerinner(tl(list),from)
else false
in
inner(list)
end;
The error messages are:
test.txt:7.34-7.44 Error: unbound variable or constructor: innerinner
test.txt:3.2-9.6 Error: unresolved flex record
(can't tell what fields there are besides #1)
test.txt:10.2-13.13 Error: unresolved flex record
(can't tell what fields there are besides #2)
uncaught exception Error
raised at: ../compiler/Toplevel/interact/evalloop.sml:66.19-66.27
....
I am a kind beginner of ML programming. Could anyone teach me what is wrong?

You have quite a few things going on here. If we first look at the errors you are getting.
unbound variable or constructor: innerinner
In sml you can't "use" stuff before it has been declared. It is easily fixed in your case by
swapping the function declarations around, and thus declaring innerinner before inner.
If you ever end up in a case where you want to for example declare two mutually recursive
functions, then this is not an option. In this case you would have to use the keyword and.
unresolved flex record
This is a bit more complicated. It is a type error and has something to do with the fact
that tuples are represented as records internally (I would recommend you go read about
it). Thus when you don't supply enough information, the type system will complain.
I think this QA explains it quite good. In summary, you can't have unbounded tuples
and thus you need to make it clear to the type system how many elements it contains. This
could be done by explicitly type annotating the function declaration.
However in general you ought to use pattern matching instead, as often as feasible.
In general you should always use pattern matching rather than tuple selectors (#1, #2, ...), or list selectors (hd or tl). You just saw why tuple selectors can be "bad" but using list selectors without testing whether or not the list is empty first will give you runtime errors (exceptions).
Putting in such test cases in your code will "blow it up" and make it messy to read. But if you use pattern matching instead you will have some nice clear cut cases in your function definition.
Also often you will tend to writer less code (in my opinion).
Btw, you don't need to put parentheses around single arguments to functions, such as you main definition of the test function.
All in all your function could look something like this:
fun test list =
let
fun innerinner ((x1, x2)::xs,from) =
if x1 = from then true
else innerinner(xs,from)
| innerinner ([], from) = false
fun inner ((x1, x2)::xs) = innerinner(xs,x1)
| inner [] = false
in
inner(list)
end

Related

Conversion from ocaml to rescript "Did you forget a `=>` here?" syntax error

Trying to convert this OCaml code to Rescript
let emptyEventHandler = ((((fun _ev -> ())
[#bs ]) : Web.Node.event_cb) : Web.Node.event_cb)
And that is what I have got after the conversion
let emptyEventHandler: Web.Node.event_cb = ((. _ev) => (): Web.Node.event_cb)
the error is Did you forget a `=>` here? (at the end)
Does anyone know if this is caused by the syntax changes they made on Rescript and any idea on how can this be fixed?
The original OCaml has a duplicate type annotation for some reason. This is valid in OCaml because everything is an expression, and every expression can have a type annotation, but is completely redundant. One possible reason for this happening is that the code might have been converted between OCaml and Reason too many times.
Rescript doesn't seem to support this case. It prefers type annotations on bindings and doesn't seem to support type annotations on expressions in general. But since Rescript is still represented by OCaml's AST, which does not make this distinction, it seems it will only take the first type annotation of a binding expression leaving the rest as-is and producing invalid Rescript code.
I'd consider this a bug since I think it should produce an error instead of invalid code, but either way the fix is simple, just remove the extraneous type annotation.
In OCaml it would then become:
let emptyEventHandler = (((fun _ev -> ()) [#bs]) : Web.Node.event_cb)
And in Rescript:
let emptyEventHandler: Web.Node.event_cb = (. _ev) => ()

crystal class with macro not compiling

for
class Y
def initialize(#a : String)
end
getter a
end
class X
macro test(name)
#{{name}} = y.{{name}}
end
#a : String
def initialize(y : Y)
test a
end
end
I got
instance variable '#a' of X was not initialized directly in all of the 'initialize' methods, rendering it nilable. Indirect initialization is not supported.
why? and set #a to nil did solve the problem but that's not a good workaround in my opinion.
Is it a bug, a design limit or just I'm not doing the right thing?
Yes, currently this is a design limitation. Quoting Ary from https://github.com/crystal-lang/crystal/issues/2731
Yes, this is expected behaviour. initialize must be simple enough for the compiler to analyze. A macro might be redefined in a subclass so resolving init is not trivial for a first pass.
This is a "won't fix" for me, or maybe we can mark it as an enhancement, but it won't happen soon (maybe never)
There's a hack I introduced to make initialization via macro possible: if {{#type}} is mentioned then the compiler will lazily check the method on call. It's not documented, though. And it has several bugs. But for now it might be okay.

Declaring a function without printing the signature [SML]

Is it possible to declare a function in SML without printing the signature?
I found out that you can print a string without printing val it = () : unit by doing:
val _ = print("Test1");
Is it possible to the same with functions? something like:
val _ = fun foo x = x + 5;
foo 10;
The following program won't compile in SML.
I'm know that I can use let\local but then I can't use them outside the closure. Also I am looking for a way, without importing additional libraries.
What you ask of relates only to the REPL, as function signatures are only printed in the REPL. You can avoid for functions (or other value declarations) to show up by defining them in a local scope, as you suggest (let, local or opaque struct).
A little hack is that multiple re-definitions in a row will yield the latest definition, but then you still need one at the end.
If you want to re-use a value in your code without the REPL printing it, perhaps you are looking to completely disable REPL declaration output, or run a compiled binary?
In Moscow ML you can run the REPL without declaration output with
mosml -quietdec file.sml
But with SML/NJ and others I don't know.

camlp4 syntax extension, parser error

I created a syntax extension that allow the definition of a type as
type.yjson type_name {
/* type_declaration */
}
to be able to build a record value directly from a json file.
The syntax extension insert a module and the function necessary to do so.
Until here, no problem. The syntax extension do exactly what I wanted.
I start having some issue if I want to use "yjson" at some other place in my code (i.e:function parameter).
Here what I tried:
EXTEND Gram
str_item:
[
[ KEYWORD "type"; KEYWORD "."; "yjson"; tdl_raw = type_declaration ->
Here the error I get when I use "yjson" as a function parameter
[fun_binding] expected after [ipatt] (in [let_binding])
I don't really understand what happen here. It doesn't seems like the rule have been match, so why do I get a parse error ?
I do not perfectly understand the P4's mechanism around this, but [ [ "blahblah" -> ... makes blahblah as a new keyword of the language, so you can no longer use blahblah as a function argument.
To see this, try preprocess your pa_*.ml by camlp4of and see how "blahblah" is expanded to Gram.Skeyword "blahblah". It seems that this Skeyword _ is passed to Structure.using via Insert.insert of P4 and the string is registered as a new keyword.
To keep yjson usable as a normal variable, use id = LIDENT instead of "yjson" in your rule, then check id's content is "yjson" or not in your action.
If I can make a slightly off-topic remark, I think it's wrong to design a custom syntax for type-directed code generation, when there already exist two different syntaxes (one for type_conv and one for deriving), one of which (type-conv) is becoming a de facto standard.
type foo = {
...
} with json
If you pick a syntax for this, you should use this one unless you have very good reasons not to. In fact, type-conv itself is a helper utility to let you write your own type-directed code generators, so you may as well use type-conv directly for what you're trying to do.
(You probably know about Martin Jambon's Atdgen, which made a conscious choice not to use Camlp4; there is ongoing work by Alain Frisch to support annotations directly in the OCaml syntax, but that's not yet ready for consumption.)

OCaml: Throw away return value in imperative code

How do I successfully throw away the return value of a function and treat it as if it's returning unit (for side-effects, obviously). The obvious approach is to do this:
let foo = begin
some_ignored_thing ();
actual_return
end
However, the compiler complains (with a warning) that the return type of some_ignored_thing isn't unit.
I could invent my own method, such as:
let ignore a = ()
Which seems at least concise and flags that something's going on, but is there anything in the language/stdlib that achieves the same thing? I'd have thought it would be a relatively common use case.
Indeed, there is an ignore : 'a -> unit function that does exactly this.
The compiler actually knows about ignore and hard-code a specific behavior that is generally very useful, but can occasionally be inconvenient: by default, ignoring a function (anything with a type of the form foo -> bar) will raise a warning.
The reason for this is that forgetting to add the last argument of a function is a relatively common mistake. You may write for example
ignore (List.map (fun x -> foo bar))
while you meant to write
ignore (List.map (fun x -> foo bar) li)
and the effects you expect to see applied are not.
So ignore will raise a warning in this case, which your hand-coded let ignore x = () does not do. People also sometimes write
let _ = foo in ...
to ignore foo, but this suffer from the same downside (it's easy to be wrong about what the type actually is). Kakadu recommends to use a type annotation there, and that's a reasonable advice.
(Some people also use let _ = ... for the "main" expression of their program. I recommend to rather use let () = ... for this same reason that it forces more type precision.)
Finally, some people prefer to use the let _ = ... form because they are in situations where using ; would force them to add parentheses or begin..end. I recommend that you always add parentheses or begin..end in these cases, because it's easy to shoot yourself in the foot with that -- obscure precedence rules for if..then..else.. for example.