OCaml: Bidirectional reference - ocaml

here is a code snippet I wrote.
let trans_binop _ =
let l = trans_exp lexp in
B.binop_build op l r
let trans_exp exp =
match exp with
| _->
trans_binop binop
The above code is simplified. And these two functions are defined inside one Module. The problem is that: the first function needs to refer to the second one, while the second one needs to refer to the first.. Then it just cannot compile.
I basically don't want to put one let expression into another one, because I think it is not decent logically..
Could any one give me some help on this question? Thanks

Use and to declare mutually recursive functions
let rec trans_binop _ =
let l = trans_exp lexp in
B.binop_build op l r
and trans_exp exp =
match exp with
| _->
trans_binop binop

You have to define your functions as mutually recursive. That means you have to use the keyword and in the place of the second let. See also https://ocaml.org/learn/tutorials/labels.html

Related

or-pattern on datatype. Partial as?

Trying to cobble together a lambda calculus interpreter as a noob project and I have come upon a syntax problem I cannot quite figure out.
Problem being that two constructors of a type behaves the same in some respects and I would like to avoid code duplication. See code below.
type term =
| Lam of string * term * term
| Pi of string * term * term
let rec subst x t s = match s with
| Lam (y,r,q) | Pi (y,r,q) ->
if x = y then LAMORPI (y, subst x t r, q)
else [...]
What I think are called or-patterns seemed like a good fit but I cannot get it to work. Figured perhaps that is what as is for, but I cannot seem to partially as something, which is what I had in mind for LAMORPI to be doing. This case seems like it would have a neat or commonly used idiomatic solution but my google-fu is not strong enough.
What is a usual or otherwise possible solution for this?
It is not possible to use or-pattern in expressions. (And this potential feature raises some issues: see http://gallium.inria.fr/blog/pattern-synonyms-as-expressions for a discussion)
One possibility is to refactor your type to expose the fact that the two constructors only differ by a tag:
type kind = Lam | Pi
type term =
| LamPi of tag * string * term * term
| ...
let rec subst x t s = match s with
| LamPi (tag,y,r,q) ->
if x = y then LamPi (tag, y, subst x t r, q)
else ...

How to partially match a pattern in OCaml

I have a list lst of objects of type value where
type value = A of int | B of bool | C of string
In doing some matching on the the list, I tried to write
match lst with
| A x :: val :: tl -> ...
and got an exception saying that in the variable val a pattern was expected. I am assuming this is because in the head of the list I matched on a value variant, but for val I wanted to capture all possible next entries in the list. I can think of some ways around them, like writing several cases for the several variants of val. But since I want to do the same basic thing no matter what val is, that seems like a very inelegant solution. Is there a better solution?
Elaborating an answer based on glennsl's comment, I assume this snippet entered into the top level is reproducing the syntax error you're hitting:
since val is a reserved keyword, it is not legal to use it in pattern matches. The error is saying that the underlined token val is triggering a syntax error since it is expecting something that could be part of a pattern.
The following should compile without any problems (using some random values for example):
type value = A of int | B of bool | C of string
match [A 1; B true; C "foo"] with
| A x :: v :: tl -> Some (x, v)
| _ -> None
And this is simply due to the replacement of the keyword val with the variable v in the pattern.

Check if a word is in a list OCAML using fold

Suppose I want to extract a 4-letter word out of 6-letter word, say "hank" out of "thanks". Suppose there is also a list of 4-letter words that makes sense and I want to check that whether the 4-letter word I just extracted makes sense (i.e if it shows up in the list of 4-letter words) and then I want to return a list of all 6-letter words from which extracted meaningful 4-letter words come.
My thought is:
let is_4_init lst =
let acc = ([]) in
let f (group) x =
let y = String.sub x 1 4 in
if List.mem y my_4words_list then ([x]) in
let (final_group) = List.fold_left f acc lst in final_group
Error: This variant expression is expected to have type unit
The constructor :: does not belong to type unit
why is this the case?
Thank you!
If you use if ... then without an else, then the type of the result must be unit. That's because the type needs to be the same for both cases. unit is the type of the value (), and is used when the result of an expression isn't particularly interesting.
Your function f should be returning an accumulated result, so it does return an interesting result. Returning unit is not what you want. You need to figure out what f should return when the test is false.
As a side comment, it's somewhat notable that you're not using the parameter named group anywhere.

variable gets forgotten after print statement

Why does this compile?
fun foo (h::t) =
h = hd(t);
But this does not
fun foo (h::t) =
PolyML.print (h::t);
print "\n";
h = hd(t);
?
Value or constructor (h) has not been declared Found near =( h, hd(t))
Value or constructor (t) has not been declared Found near =( h, hd(t))
Exception- Fail "Static errors (pass2)" raised
I think your frustration with the language prevents you from solving your problem(s) more than the limitations of the language. As I said in a previous answer, semicolons cannot be used like you used them. You need to wrap those statements inside parentheses:
fun foo (h::t) =
(
PolyML.print (h::t);
print "\n";
h = hd(t)
)
Furthermore, you first snippet doesn't need a semicolon:
fun foo (h::t) =
h = hd(t)
Here's the thing, in SML semicolons are not used to terminate statements, they're used to separate expressions. Think of ; as a binary operator, just like + or -. With the added constraint that you need parentheses around.
Also, you're probably using the = operator in the wrong way inside h = hd(t). It's not assignment, it's an equality check, just like == in other languages. If you want assignment, you need a ref type.
It's probably better to ask what exactly you're trying to solve, because at this point you're totally misunderstanding the syntax and semantics of SML and we can't really write a tutorial on in here.

Look for a trick to iter on ocaml type constructors

I have an ocaml type :
type t = A | B | ...
and a function to print things about that type :
let pp_t fmt x = match x with
| A -> Format.fprintf fmt "some nice explanations about A"
| B -> Format.fprintf fmt "some nice explanations about B"
| ...
How could I write a function to print all the explanations ? Something equivalent to :
let pp_all_t fmt =
Format.fprintf fmt A;
Format.fprintf fmt B;
...
but that would warn me if I forget to add a new constructor.
It would be even better to have something that automatically build that function,
because my problem is that t is quiet big and changes a lot.
I can't imagine how I can "iterate" on the type constructors, but maybe there is a trick...
EDIT: What I finally did is :
type t = A | B | ... | Z
let first_t = A
let next_t = function A -> B | B -> C | ... | Z -> raise Not_found
let pp_all_t fmt =
let rec pp x = pp_t fmt x ; try let x = next_t x in pp x with Not_found -> ()
in pp first_t
so when I update t, the compiler warns me that I have to update pp_t and next_t, and pp_all_t doesn't have to change.
Thanks to you all for the advices.
To solve your problem for a complicated and evolving type, in practice I would probably write an OCaml program that generates the code from a file containing a list of the values and the associated information.
However, if you had a function incr_t : t -> t that incremented a value of type t, and if you let the first and last values of t stay fixed, you could write the following:
let pp_all_t fmt =
let rec loop v =
pp_t fmt v;
if v < Last_t then loop (incr_t v)
in
loop First_t
You can't have a general polymorphic incr_t in OCaml, because it only makes sense for types whose constructors are nullary (take no values). But you can write your own incr_t for any given type.
This kind of thing is handled quite nicely in Haskell. Basically, the compiler will write some number of functions for you when the definitions are pretty obvious. There is a similar project for OCaml called deriving. I've never used it, but it does seem to handle the problem of enumerating values.
Since you say you want a "trick", if you don't mind using the unsafe part of OCaml (which I personally do mind), you can write incr_t as follows:
let incr_t (v: t) : t =
(* Please don't use this trick in real code :-) ! See discussion below.
*)
if t < Last_t then
Obj.magic (Obj.magic v + 1)
else
failwith "incr_t: argument out of range"
I try to avoid this kind of code if at all possible, it's too dangerous. For example, it will produce nonsense values if the type t gets constructors that take values. Really it's "an accident waiting to happen".
One needs some form of metaprogramming for such tasks. E.g. you could explore deriving to generate incr_t from the Jeffrey's answer.
Here is a sample code for the similar task : https://stackoverflow.com/a/1781918/118799
The simplest thing you can do is to define a list of all the constructors:
let constructors_t = [A; B; ...]
let pp_all_t = List.iter pp_t constructors_t
This is a one-liner, simple to do. Granted, it's slightly redundant (which gray or dark magic would avoid), but it's still probably the best way to go in term of "does what I want" / "has painful side effects" ratio.