Can we peek out partially inferred typing info. from Ocaml toplevel/compiler for a program that does not compile? - debugging

I would like to know, in Ocaml, whether a partial typing info. can be drawn by some existed functionality of toplevel/compiler, for a program that does not compile? Let me explain.
In Ocaml, it's well known that inferred typed can be retrieved by -annot file. However, sometimes we have a piece of code that does not compile due to some typing error. It gives a error exported to the toplevel, of this pattern
"This expression has type A, but was expected type B"
An artificial example would be
# let x =
let y = 5 in
not y;;
Characters 32-33:
not y;;
^
Error: This expression has type int
but an expression was expected of type bool
The programmer of this piece of code should understand well the 2nd part of this message, i.e.,
"y is expected of type bool", because of the "not y" part. However, she/he might have some difficulty to understand the 1st part of this error message: how this "y" is inferred to have type "int"? Thus it would be interesting to have a partial set of inferred types, before the type conflicts are raised. For the example above, one would like the interpreter tells that the first "y" (from "let y = 5") is of type int, by which I will know the reason why the second "y" (from "not y") is infered to be of type int.
Could you tell me whether the described functionality is already provided by some ocaml interpreter/compiler?
In general words, my question is: can ocaml toplevel, or its interpreter, yield partially inferred types that user can retrieve in order to more efficiently find the source of their typing error?
This question might not make sense because of the non-uniqueness of the partially inferred type annotation. However, the example example should show that at least for some cases, and some partially inferred types have its usage.
Thank you for your ideas.

The type annotations by generated by the -annot switch are available even if the program did not compile. You'll see types for the expressions that the compiler got through, and some of them may be incomplete. This doesn't tell you the compiler's reasoning for inferring the types, but it does tell you how far the compiler went and lets you explore what it's inferred.
For example, with this source code:
let x = [(let y = 5 in not y); true];;
x has the type _a list (the compiler hasn't gotten far enough to figure out _a).
y has the type int.
not has the type bool -> bool.
The error message is that the second occurrence of y has the type int (and we've seen where it was inferred) but the context expects the type bool (and we can see that, since not is a function whose argument type is bool).
I don't know how to see these types from the toplevel, but if you have a source file with your code, you can run ocamlc -c -annot, open the source in a suitable editor (such as Emacs) and view the inferred types whether the compilation succeeded or not.

Related

Is there a way to refer to the result of the previous command in PSCi?

Coming from Haskell, I'm accustomed to using it to refer to the result of the previous command in GHCi:
ghci> 1+1
2
ghci> :type it
it :: Num a => a
ghci> it*2
4
I went looking to see if there was something similar in the PureScript REPL, but I couldn't find anything about it on the "Differences from Haskell" page in the PureScript docs (which makes a certain kind of sense now that I've had some time to think about it, since it is a specific feature of GHCi, not of the Haskell language itself), or in the PSCi documentation. In GHCi I can :show bindings to discover that it has been bound, but PSCi's :show command doesn't accept the bindings argument, and from the built-in PSCi help :? it's not obvious to me if there's a different command that does the same thing. (I know PSCI's :browse lets you examine the functions from a specific module, so since errors reported in PSCi often begin with Error found: in module $PSCI I tried :browse $PSCI, but this produces an indentation error.)
Some errors I've encountered seem to suggest that PSCi is trying to bind the result of a computation to the name it (I've cut some whitespace but otherwise this is copied verbatim from a fresh spago repl session in a toy project—note the final line, in value declaration it):
> import Prelude
> 1+'a'
Error found:
in module $PSCI
at :1:3 - 1:6 (line 1, column 3 - line 1, column 6)
Could not match type
Char
with type
Int
while checking that type Char
is at least as general as type Int
while checking that expression 'a'
has type Int
in value declaration it
But after a successful computation, it isn't available:
> 1+1
2
> it
Error found:
at <internal>:0:0 - 0:0 (line 0, column 0 - line 0, column 0)
The value of it is undefined here, so this reference is not allowed.
This is a CycleInDeclaration error, which is different from the UnknownName error produced when trying to use some other undefined name like x or foo. This all makes me suspect there is something special going on with it and I'm just missing something obvious about how to make it available for use in the REPL, but as someone brand new to PureScript, I'm not sure where to look next.

Is F# Constructed Type syntax special?

I was curious about F#'s "constructed type" syntax. It's documented here.
type-argument generic-type-name
or
generic-type-name
With the following examples:
int option
string list
int ref
option<int>
list<string>
ref<int>
Dictionary<int, string>
I was curious if there's anything special about the "backwards" syntax, with the parameter before the type, or if it's just sugar for generic types with one parameter. The following is valid:
type 'a MyOption = // MyOption<'a> also works
| MySome of 'a
| MyNone
But I could not get it to work with multiple type parameters. Why do F# developers prefer this syntax for types with one parameter? Is it possible or desirable to make it work with two?
The backwards syntax is a legacy from OCaml. Personally, I never use it. If you really want to, you can make it work with multiple type arguments like this:
type MyMap = (int, string) Map
However, this generates a pointed warning (that might soon become an error):
This construct is for ML compatibility. The syntax '(typ,...,typ) ident' is not used in F# code. Consider using 'ident<typ,...,typ>' instead. You can disable this warning by using '--mlcompatibility' or '--nowarn:62'.
Bottom line, I would recommend always using .NET syntax instead: MyOption<'a> instead of 'a MyOption.
Why do F# developers prefer this syntax for types with one parameter?
Not all of us do. I love F# and am in awe of it, but find the OCaml style distracting.
It gets especially confusing when the two styles are mixed - compare the readability of Async<Result<int,string list>> list with that of List<Async<Result<int,List<string>>>>.
Here is a thread with some arguments from both sides from fslang suggestions, which I think led to the deprecation of OCaml-style for everything but list, option and a few others.
I find it regrettable that the OCaml style is specified as the preferred option (for these types) in the various style guides, and used throughout the core libraries, while there is such a strong drive to make the language more accessible to newcomers. It definitely adds to the learning curve, as documented in this question,
and here,
here,
here,
here,
here.
Is it possible or desirable to make [OCaml style naming] work with two [type parameters]?
I think a better question is: "Is it possible to only use .NET style?".
Unfortunately the tooling shows types the way they are declared, and the core libraries consistently use OCaml style. I have asked Rider about always showing declarations .NET style in code vision, who referred me to FSharp compiler services. I have not (yet) investigated that avenue further.
In our own code we have taken to overriding the OCaml signatures of functions that ship with F# and other libraries as we come across them, for example:
[<AutoOpen>]
module NoCaml =
module List =
/// Returns a new collection containing only the elements of the collection for which the given predicate returns "true"
let filter = List.filter : ('a -> bool) -> List<'a> -> List<'a>
/// val groupBy : projection:('T -> 'Key) -> list:'T list -> ('Key * 'T list) list (requires equality and equality) 'T is 'a 'Key is 'b Applies a key-generating function to each element of a list and yields a list of unique keys. Each unique key contains a list of all elements that match to this key.
let groupBy = List.groupBy : ('a -> 'b) -> List<'a> -> List<'b * List<'a>>
// etc.
This solves the problem in almost all cases (some exceptions like list construction using [] remain, and need to be overridden at the point of declaration).
I'm not sure what influence this has on performance at runtime - hopefully the extra function calls are optimised away.

How to get Type representation from name via reflection?

Is there a way to use the reflection libraries in Go to go from the name of a type to its Type representation?
I've got a library where the user needs to provide Type representations for some code generation. I know it must be possible (in a sense) because they can just create a variable of that type and call the TypeOf function, but is there a way to circumvent this and just get representation from the name?
The question is not quite explicit, it can be interpreted in 2 ways, to one of which the answer is no, not possible; and the other to which the answer is yes, it's possible.
At runtime
If the type name is provided as a string value, then at runtime it's not possible as types that are not referred to explicitly may not get compiled into the final executable binary (and thus obviously become unreachable, "unknown" at runtime). For details see Splitting client/server code. For possible workarounds see Call all functions with special prefix or suffix in Golang.
At "coding" time
If we're talking about "coding" time (source code writing / generating), then it's possible without creating / allocating a variable of the given type and calling reflect.TypeOf() and passing the variable.
You may start from the pointer to the type, and use a typed nil pointer value without allocation, and you can navigate from its reflect.Type descriptor to the descriptor of the base type (or element type) of the pointer using Type.Elem().
This is how it looks like:
t := reflect.TypeOf((*YourType)(nil)).Elem()
The type descriptor t above will be identical to t2 below:
var x YourType
t2 := reflect.TypeOf(x)
fmt.Println(t, t2)
fmt.Println(t == t2)
Output of the above application (try it on the Go Playground):
main.YourType main.YourType
true

How is type inference implemented in a language like C++11 or Go?

I saw this question here, but it doesn't answer what I had in mind in particular detail.
If languages like Go or C++11 don't use an inference algorithm like Damas-Milner, what exactly do they do? I don't think it's as simple as taking the type on the right hand side because what if you had something like:
5 + 3.4
How would the compiler decipher what type that is? Is there any algorithm that isn't as simple as
if left is integer and right is float:
return float;
if left is float and right is integer:
return float;
etc... for every possible pattern
And if you could explain things in simple terms that would be great. I'm not studying compiler construction or any of the theoretical topics in great detail, and I don't really speak functional languages or complex mathematical notation.
I don't think it's as simple as taking the type on the right hand side
For basic type inference of the form auto var = some_expression;, it is exactly that simple. Every well-typed expression has exactly one type and that type will be the type of var. There will be no implicit conversion from the type of the expression to another type (as there might be if you gave an explicit type for var).
what if you had something like:
5 + 3.4
The question "What is the type of 5 + 3.4?" isn't specific to type inference, C++ compilers always had to answer this question - even before type inference was introduced.
So let's take a step back and look at how a C++ compiler typechecks the statement some_type var = some_expression;:
First it determines the type of some_expression. So in code you can imagine something like Type exp_type = type_of(exp);. Now it checks whether exp_type is equal to some_type or there exists an implicit conversion from exp_type to some_type. If so, the statement is well-typed and var is introduced into the environment as having the type some_type. Otherwise it is not.
Now when we introduce type inference and write auto var = some_expression;, the equation changes as such: We still do Type exp_type = type_of(exp);, but instead of then comparing it to another type or applying any implicit conversions, we instead simply set exp_type as the type of var.
So now let's get back to 5 + 3.4. What is its type and how does the compiler determine it? In C++ its type is double. The exact rules to determine the type of an arithmetic expression are listed in the C++ standard (look for "usual arithmetic conversions"), but basically boil down to this: Of the two operand types, pick the one that can represent the greater range of values. If the type is smaller than int, convert both operands to int. Otherwise convert both operands to the type you picked.
In code you'd implement this by assigning each numeric type a conversion rank and then doing something like this:
Type type_of_binary_arithmetic_expression(Type lhs_type, Type rhs_type) {
int lhs_rank = conversion_rank(lhs_type);
int rhs_rank = conversion_rank(rhs_type);
if(lhs_rank < INT_RANK && rhs_rank < INT_RANK) return INT_TYPE;
else if(lhs_rank < rhs_rank) return rhs_type;
else return lhs_type;
}
Presumably the rules for Go are somewhat different, but the same principles apply.

Unrestricted variable name declaration in Mercury

I would like to declare a data type in Mercury that can have a variable number of values and names. For instance :
type goal ---> pick; give; come.
has three variables/values.
I want something like:
type myplayer ---> de value declaration here.
That's the number of variables are not restricted or fixed.
So I can use myplayer to declare values/variables like v1, v2, v3 and v4. The second time I can use it to declare something like: a, b, c, d, e, z, aa, ab and az.
The number of the values are not restricted and the names are also not fixed.
I am new in Mercury.
As others have said, this is simply impossible in Mercury - which is deliberate.
What you might want though, if you want a type that expresses: v1 v2 v3... etc is:
:- type my_type
----> v(int).
:- func name(my_type) = string.
name(v(Num)) = formst("v%d", [i(Num)]).
The type expresses v of all integers, and the function name can be used to 'pretty-print' values of this type.
What you directly ask for, simply cannot be done. Given
:- type question
---> truth(string, bool)
; blank(string, string)
; multiple(string, string, list(string)).
additional kinds of questions can only be added by extending this type where it is defined, and recompiling the module - and making a lot of other changes, too, as previously deterministic code like
answer(truth(_, yes)) = "true".
answer(truth(_, no)) = "false".
answer(blank(_, A)) = A.
answer(multiple(_, A, _)) = A.
would fail when given your new question type. Being told at compile-time where you've failed to update your program to reflect the addition of a "pick-all-the-right-answers" type of question is a good part of the reason you have a question type at all, instead of say lists of strings [["Are foxes pretty?", "true"], ["Green foxes are ____", "adorable!", "fake", "evidence of animal cruelty"]] for your question bank.
What you ask for cannot be done. However, what you actually want to do -- the end to which you thought 'variable numbers of types' would be an helpful means -- can surely be accomplished in some other way. I can't tell what way that is, as I can't tell why you wanted to do this from your question. Maybe you'd benefit from reading over discriminated unions or typeclasses in the language reference.
As far as I understand this question. You want some Prolog-like behavior. I.e without typed predicates. In statically typed system you always can achieve such behavior by handling that by yourself. A lot of time ago I saw such example in Turbo Prolog (they implemented ISO prolog in terms of Turbo/Visual Prolog).
Consider something like (I'm not sure it is correct):
:- type any_type ---> atom_value(string)
; number_value(int)
; struct_value(any_type, list(any_type)).
guess(atom_value("v1")).
guess(atom_value("a")).
guess(atom_value("aa")).
guess(number_value(42)).
guess(struct_value(atom_value("pair"), [number_value(3), number_value(4)])).

Resources