* [Caml-list] Question on "more general"
@ 2017-04-19 10:40 Kenichi Asai
2017-04-19 10:46 ` Leo White
0 siblings, 1 reply; 6+ messages in thread
From: Kenichi Asai @ 2017-04-19 10:40 UTC (permalink / raw)
To: caml-list
[-- Attachment #1: Type: text/plain, Size: 617 bytes --]
Dear OCaml type inference experts,
If I infer the type (using Typemod.type_structure) of:
let a = 1 in fun x -> 1
and see if the type of x is more general (using Ctype.moregeneral)
than the type of a type variable (Btype.newgenvar ()), I obtain yes
(since the type of x is 'a which is more general (or equal) than a
newly created type variable, I guess). If I do the same for:
let a = assert false in fun x -> 1
I obtain no, although it still seems that the type of x is the same
'a. (See attached file for the concrete program I executed. I used
OCaml 4.04.0.) Why?
Thank you in advance!
--
Kenichi Asai
[-- Attachment #2: main.ml --]
[-- Type: text/plain, Size: 1764 bytes --]
open Asttypes
open Ast_helper
open Types
open Typedtree
open Parsetree
(* some helper functions *)
(* extract_typ : Typedtree.structure -> type_expr *)
let extract_typ str = match str.str_items with
[{str_desc = Tstr_eval ({ exp_type = typ }, _)}] -> typ
| _ -> failwith "cannot happen"
(* split_arrow : type_expr -> type_expr * type_expr *)
let rec split_arrow typ = match typ.desc with
Tarrow (_, t1, t2, _) -> (t1, t2)
| Tlink (typ') -> split_arrow typ'
| _ -> failwith "cannot happen"
(* various expressions *)
(* 1 *)
let one : expression = Exp.constant (Const.integer "1")
(* false *)
let ff : expression = Exp.construct (mknoloc (Longident.Lident "false")) None
(* variable pattern *)
let var x : pattern = Pat.var (mknoloc x)
(* fun x -> 1 *)
let fun_x_one : expression = Exp.fun_ Nolabel None (var "x") one
(* let a = 1 in fun x -> 1 *)
let exp1 : expression =
Exp.let_ Nonrecursive [Vb.mk (var "a") one] fun_x_one
let env : Env.t = Env.initial_safe_string
(* infer type of exp1 *)
let (str1', _, _) =
Typemod.type_structure env [Str.eval exp1] Location.none
(* type of x *)
let (typx1, _) = split_arrow (extract_typ str1')
let b1 = Ctype.moregeneral env false typx1 (Btype.newgenvar ())
;; print_endline (if b1 then "true" else "false")
(* assert false *)
let assert_false : expression = Exp.assert_ ff
(* let a = assert false in fun x -> 1 *)
let exp2 : expression =
Exp.let_ Nonrecursive [Vb.mk (var "a") assert_false] fun_x_one
(* infer type of exp2 *)
let (str2', _, _) =
Typemod.type_structure env [Str.eval exp2] Location.none
(* type of x *)
let (typx2, _) = split_arrow (extract_typ str2')
let b2 = Ctype.moregeneral env false typx2 (Btype.newgenvar ())
;; print_endline (if b2 then "true" else "false")
[-- Attachment #3: Makefile --]
[-- Type: text/plain, Size: 167 bytes --]
run : main
./main
main : main.ml
ocamlfind ocamlc -package compiler-libs.common,compiler-libs.bytecomp -linkpkg main.ml -o main
clean :
rm main main.cmi main.cmo
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Question on "more general"
2017-04-19 10:40 [Caml-list] Question on "more general" Kenichi Asai
@ 2017-04-19 10:46 ` Leo White
2017-04-20 0:15 ` Kenichi Asai
0 siblings, 1 reply; 6+ messages in thread
From: Leo White @ 2017-04-19 10:46 UTC (permalink / raw)
To: Kenichi Asai; +Cc: caml users
[-- Attachment #1: Type: text/plain, Size: 1064 bytes --]
Without looking too closely at your question I would assume that is just
the value restriction.
Regards,
Leo
On 19 April 2017 at 11:40, Kenichi Asai <asai@is.ocha.ac.jp> wrote:
> Dear OCaml type inference experts,
>
> If I infer the type (using Typemod.type_structure) of:
>
> let a = 1 in fun x -> 1
>
> and see if the type of x is more general (using Ctype.moregeneral)
> than the type of a type variable (Btype.newgenvar ()), I obtain yes
> (since the type of x is 'a which is more general (or equal) than a
> newly created type variable, I guess). If I do the same for:
>
> let a = assert false in fun x -> 1
>
> I obtain no, although it still seems that the type of x is the same
> 'a. (See attached file for the concrete program I executed. I used
> OCaml 4.04.0.) Why?
>
> Thank you in advance!
>
> --
> Kenichi Asai
>
> --
> Caml-list mailing list. Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
[-- Attachment #2: Type: text/html, Size: 1848 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Question on "more general"
2017-04-19 10:46 ` Leo White
@ 2017-04-20 0:15 ` Kenichi Asai
2017-04-20 9:25 ` Leo White
0 siblings, 1 reply; 6+ messages in thread
From: Kenichi Asai @ 2017-04-20 0:15 UTC (permalink / raw)
To: Leo White; +Cc: caml users
> Without looking too closely at your question I would assume that is just the
> value restriction.
But both in the expressions:
> let a = 1 in fun x -> 1
> let a = assert false in fun x -> 1
the variable a is not used in fun x -> 1. How can the type of x be
affected by an unused binding for a around fun x -> 1?
It also seems that assert false can be used polymorphically (because
of the relaxed value restriction?):
# fun () -> let a = assert false in (a 1, a true);;
Warning 20: this argument will not be used by the function.
Warning 20: this argument will not be used by the function.
- : unit -> 'a * 'b = <fun>
--
Kenichi Asai
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Question on "more general"
2017-04-20 0:15 ` Kenichi Asai
@ 2017-04-20 9:25 ` Leo White
2017-04-20 15:13 ` Kenichi Asai
0 siblings, 1 reply; 6+ messages in thread
From: Leo White @ 2017-04-20 9:25 UTC (permalink / raw)
To: Kenichi Asai; +Cc: caml users
[-- Attachment #1: Type: text/plain, Size: 1595 bytes --]
The expression:
let a = assert false in
fun x -> 1
is not a syntactic value, so because of the value restriction it has type:
'_a -> int
That '_a comes from the `x` parameter.
> the variable a is not used in fun x -> 1
OCaml doesn't take account of whether `a` is used in deciding if something
is a value, although if you had written:
ignore (assert false);
fun x -> 1
then it would have been a value.
I suspect the part you are missing is that generalization happens as part
of `let` (and `match`, class definitions, polymorphic record creation,
etc...). If you had written:
let a = assert false in
let f = fun x -> 1 in
f
then the type associated with `x` would have been generalized as part of
the definition of `f` although the resulting function would still have type:
'_a -> int
Regards,
Leo
On 20 April 2017 at 01:15, Kenichi Asai <asai@is.ocha.ac.jp> wrote:
> > Without looking too closely at your question I would assume that is just
> the
> > value restriction.
>
> But both in the expressions:
>
> > let a = 1 in fun x -> 1
> > let a = assert false in fun x -> 1
>
> the variable a is not used in fun x -> 1. How can the type of x be
> affected by an unused binding for a around fun x -> 1?
>
> It also seems that assert false can be used polymorphically (because
> of the relaxed value restriction?):
>
> # fun () -> let a = assert false in (a 1, a true);;
> Warning 20: this argument will not be used by the function.
> Warning 20: this argument will not be used by the function.
> - : unit -> 'a * 'b = <fun>
>
> --
> Kenichi Asai
>
[-- Attachment #2: Type: text/html, Size: 2604 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Question on "more general"
2017-04-20 9:25 ` Leo White
@ 2017-04-20 15:13 ` Kenichi Asai
2017-05-12 13:49 ` Ivan Gotovchits
0 siblings, 1 reply; 6+ messages in thread
From: Kenichi Asai @ 2017-04-20 15:13 UTC (permalink / raw)
To: Leo White; +Cc: caml users
Thank you! That's very clear. So instead of writing assert false, if
I could write a "value" of type 'a, then the type of x becomes 'a.
I confirmed it with the following file:
--------------------------------
let v = assert false
let g1 = let a = v in
let f = fun x -> 1 in
f
let g2 = let a = assert false in
let f = fun x -> 1 in
f
--------------------------------
If I see the types of variables via "ocamlc -i", I obtained:
val v : 'a
val g1 : 'a -> int
val g2 : '_a -> int
Thank you again!
--
Kenichi Asai
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Question on "more general"
2017-04-20 15:13 ` Kenichi Asai
@ 2017-05-12 13:49 ` Ivan Gotovchits
0 siblings, 0 replies; 6+ messages in thread
From: Ivan Gotovchits @ 2017-05-12 13:49 UTC (permalink / raw)
To: Kenichi Asai; +Cc: Leo White, caml users
[-- Attachment #1: Type: text/plain, Size: 1883 bytes --]
A small update.
But before the update, let me clarify the original reason, why the
expression `let a = assert false in fun x -> 1` is not generalized. The
reason is because the `assert false` is not nonexpansive (sorry for the
double negation). A nonexpansive value, in OCaml compiler parlance, is a
value that has "no _observable_ side effects". The `assert false` is
currently typed as a special expression, that is assumed to have a side
effect (i.e., it is expansive). Thus, it is basically treated the same as
`let a = print_int 1 in fun x -> 1` that is also not generalized, as the
evaluation of the `print_int 1 in fun x -> 1` has some effect.
Apparently, the assumption that `assert false` is expansive was too
conservative, as it was already subsumed (in some cases) with the value
restriction relaxation. So it will be relaxed soon, see GPR#1142 [1]. And
soon both of your functions will have the same type.
[1]: https://github.com/ocaml/ocaml/pull/1142
On Thu, Apr 20, 2017 at 11:13 AM, Kenichi Asai <asai@is.ocha.ac.jp> wrote:
> Thank you! That's very clear. So instead of writing assert false, if
> I could write a "value" of type 'a, then the type of x becomes 'a.
>
> I confirmed it with the following file:
>
> --------------------------------
> let v = assert false
>
> let g1 = let a = v in
> let f = fun x -> 1 in
> f
>
> let g2 = let a = assert false in
> let f = fun x -> 1 in
> f
> --------------------------------
>
> If I see the types of variables via "ocamlc -i", I obtained:
>
> val v : 'a
> val g1 : 'a -> int
> val g2 : '_a -> int
>
> Thank you again!
>
> --
> Kenichi Asai
>
> --
> Caml-list mailing list. Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
[-- Attachment #2: Type: text/html, Size: 2929 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2017-05-12 13:49 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-19 10:40 [Caml-list] Question on "more general" Kenichi Asai
2017-04-19 10:46 ` Leo White
2017-04-20 0:15 ` Kenichi Asai
2017-04-20 9:25 ` Leo White
2017-04-20 15:13 ` Kenichi Asai
2017-05-12 13:49 ` Ivan Gotovchits
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).