Can I expand a typedef in SMLNJ? - sml

So I was writing up some code in standard ML, and trying to compile it with smlnj. I got the following error:
Error: operator and operand don't agree [tycon mismatch]
operator domain: unit -> Absyn.fundec
operand: unit
-> (pos * pos) *
((string * int) * (string * int) * Absyn.tp * Absyn.tp
* Absyn.exp)
Now, this looks like it should be a type match based on my cursory inspection of the types. I'm not going to tell you them since I want a general solution, not the bug in my code.
Is it possible to expand both types into the base datatypes so I can figure out how they differ? With all these typedefs floating around things get confusing, and digging through .sml files for all the definitions and writing the expansion on paper seems like a tedious solution.
I would love to say something like:
typeof Absyn.fundec
and figure out what the heck kind of expression might produce a valid fundec.

As Absyn.fundec is not a standard type as int, bool, etc. there must be a datatype or a type declaration which should tell you exactly how the Absyn.fundec type is defined.

Related

How is the rules of calculating a value named in C++

Ok, this is a hard (for me) to explain what exactly I'm asking for, but I'll try it anyway...
I'm trying to explain to a person, who is learning C++, how an expression is calculated.
More specifically, why this:
5 / 2
gives 2 and why that:
5.0 / 2.0
gives an expected 2.5.
My explanation says it is because Integer value / Integer value = Integer value. And this is the clu of my question: how is that rule called? I always thought it is "Type Algebra", but putting that on Google shows this term is rather Haskell related.
So, is the rule describing how operations and type of expressions in C++ depends on the types of values/variables somehow called? And an extra question: is it related only to C++ (I mean: this term is used only in C++ related material)?
You are looking for topics like:
Promotion rules
Implicit conversions
Arithmetic conversions
Other stuff like operator precedence may also apply depending on the expression.

The nonfix operator in SML

I read the grammar of SML and I found out that beside infix and infixr it also contains nonfix. I tried to find some basic examples but it seems that no one uses it. Also tried to find some previous threads about that operator but there are none.
What is the idea behind nonfix? Why it seems like no one uses it?
nonfix turns an infix operator into a "regular" function on tuples. For example * is a function of type int * int -> int, but can't be called as e.g. * (2,3). If for some reason you wanted to do that, you could do the following:
nonfix *
and then * (2,3) will evaluate to 6.
Unfortunately, as an annoying side effect, you can no longer use 2 * 3.
The reason why it doesn't seem to be heavily used is that if I wanted to use * as a regular function, I could just use op: For example, op * (2,3) evaluates to 6. The annoyance of not being able to later on use * as an infix operator outweighs the advantage of not having to type op.

Compare real list in sml

For the next code I'm getting an error:
fun epoly(L:real list, x:real)=
= if L = [] then 0.0 else (epoly(tl(L:real list), x:real));;
Error:
stdIn:42.1-42.57 Error: operator and operand don't agree [equality type required]
operator domain: ''Z * ''Z
operand: real list * 'Y list
in expression:
L = nil
Since you're not actually asking a question, it is a little unclear what your intent is. Presumably this is attempted code that doesn't work and the accompanying error message, and the implicit question is "Why doesn't this code work? What am I doing wrong, and what can I do to improve it?" But really that's guesswork, and those are lazy questions, too.
Here's how your post could look like if my assumptions above are correct and you want positive feedback in the future:
I am trying to write a function that evaluates a polynomial with real coefficients L for the variable x.
It looks like:
fun epoly (L : real list, x : real) =
if L = [] then 0.0 else epoly(tl L, x)
Unfortunately I am getting a type error that I don't understand:
stdIn:1.35-1.91 Error: operator and operand don't agree [equality type required]
operator domain: ''Z * ''Z
operand: real list * 'Y list
in expression:
L = nil
What does this error mean, and if this is not the right way to evaluate a polynomial, then what would another way to accomplish the same thing look like?
The take-aways:
Write what your problem is, don't let others assume what your problem is. Making a question easily understood makes people want to answer your question, and describing your problem in words tells what you think is the problem, so that people don't try and answer the wrong question. In this case, your question could have been "Under what version of the Standard ML specification were reals removed as an eqtype?" and a sufficient answer would have been '97. But would you have been happy about that answer?
Once you know how to ask the right question, you can also better google around (e.g. search for: evaluate polynomial "standard ml"|sml) and find that there exists code from which you can let yourself inspire: here, here, here.
Format your code nicely and make sure it works. Use StackOverflow's Markdown to format your code nicely. The code that you posted contains artifacts from the interactive REPL (an extra =), so anyone who copy-pastes it into a REPL will get an error, will have to figure out where it occurred, fix it, and then start to think about what could be the problem, since you didn't say. A good rule is to test that the code you posted works by copy-pasting it once you've asked the question. One can easily forget to include a non-standard function.
An answer, assuming my rendition of your "question" somewhat lines up with your intent:
When you do if L = [] ... then you're using equality for lists of reals, which in turn relies on equality for reals, but reals can't be compared for equality. See the Q&A "Why can't I compare reals in Standard ML?" You can test if a list of reals is empty without comparing reals by doing e.g.:
fun epoly (L, x) =
if null L then 0.0 else epoly (tl L, x)
This is because the standard library function null uses pattern matching on lists but does not address the list's elements, whereas = assumes that elements may have to be compared. Even though that never happens in practice in the example L = [], this is still an error in the type system.
If you were comparing reals for equality, consider using an epsilon test. Besides that, consider using pattern matching instead of hd and tl because those functions can fail and crash because they're partial:
fun epoly ([], x) = 0.0
| epoly (c::cs, x) = epoly (cs, x)
All this function does is throw away its second argument x, traverse its first argument, c::cs, and do nothing with each coefficient c. Presumably, in order to evaluate a polynomial, you must do something to coefficient c and x before doing the same thing recursively on the remaining coefficients cs and x, and then somehow compose those.

Using MSVC preprocessor 'charizing' operator in Clang

I've got the following code that someone working on MSVC has given to me:
#define MAP1(x, y) map[#x] = ##y;
I'm on Xcode, using Clang, and from various google searches I've found that this is known as a 'charizing operator', and is specific to MSVC's preprocessor. Is there a way of emulating the functionality of this operator while using Clang? I've tried removing the # but got the following error message:
Assigning to 'int' from incompatible type 'const char[2]'
Would an explicit cast to 'int' work or is the charizing operator doing something different?
The stringizing operator (standard C++) converts a into "a", so the charizing operator sounds like it turns a into 'a'. You can, in the simple cases, get 'a' from "a" by taking the first character.
#define MAP1(x, y) map[#x] = static_cast<const char(&)[2]>(#y)[0];
The static_cast to const char(&)[2] ensures you get a compile-time error if you don't get a string of length 1, which is two characters if you count the trailing '\0'. A plain #y[0] would silently take the first character, regardless of the string's length.
Did you try something like #y[0]? Basically, "stringify y and take the first char" :-)
Other than that, since from the looks of it the generated statements are executed at runtime anyway, you can just stringify y, pass it to a function and have that function return the right thing.

Implement and represent polyadic operations

I'm not sure I even know how to ask this question .. In implementing a compiler I would like to allow the client to specify, say, folds on tuples. I have provided a way to curry and uncurry a function, but only because I wrote a binary operator in Ocaml and folded it over the term and type representations. The user could not write this function.
In the macro processor, the user can write this function because tuples are lists.
For curried functions, the user can easily write transformers, because the term is binary in both the target language and the Ocaml representation of the term and the typing.
But they can't do this for tuples. Here's another example: the user easily defines serial functional composition operator. But the user cannot define parallel composition: the binary version:
f1: D1 -> C1, f2: D2-> C2 --> f1 * f2: D1 * D2 -> C1 * C2
is easily written, but cannot be extended to 3 terms: here a fold would compute
f1 * (f2 * f3)
instead of
f1 * f2 * f3
[isomorphic but not equal]
The generalisation of this question is "How do I implement a polyadic programming language" which is a bit too much to ask here. What I tried to do was provide a builtin transformer:
curry: T1 * T2 * T3 ... --> T1 -> T2 -> ...
uncurry: T1 -> T2 -> .. T1 * T2 * T3
so then the user could just do folds with a binary operator:
uncurry (fold user_op (uncurry term))
but this is neither general enough nor works so well.. :)
I guess an equivalent question for Haskell would be: since Haskell has no n-ary products, the n-ary tuple constructors is simulated in the library with n functions, where each one has to be written out by hand. This clearly sucks. How would this be fixed?
[I mean, it is trivial to write a Python script to generate those n functions up to some limit n, so why is it so hard to do this in a well typed way inside the language?]
There are two components that collaborate to cause this issue:
Tuples are not auto-flattened - the parentheses in type expressions do more than group, they create distinct types that are joined by further tuples. This leads to your observation that a * (b * c) is isomorphic but not equivalent to a * b * c.
The type system does not provide a means to express algebra on tuple types. By this I mean that the type system does not have a cons operator or any equivalent for tuples; there is no way to express that a type has more or fewer tupled elements than another type.
The result is that there is no way to express the type of a function that operates on tuples of arbitrary length.
So, the short summary is that the OCaml type system lacks mechanisms to express the type of the function you are trying to write, and therefore you cannot write the function (setting aside nasty games with Obj; you could write the function, but you could not express its type to use it in a type-safe fashion).
There are basically two options.
You can make your language untyped or weakly typed. In C for example, tuples (of integers, say) can be represented as int*. Something would need to keep track of the tuples' lengths but the type system won't. I assume you do not want to go that way.
For a type-safe language, you need a very expressive type system. Namely, you need types that depend on values. The members of which are functions that return types. For example the tuple type constructor (not to be confused with the tuple constructor) could have type tuple : int -> Type -> Type.
An operation that extends a tuple could have type forall n:int. forall T:Type. tuple n T -> T -> tuple (n+1) T. Such type systems come at a cost: Typically, type inference is not recursive and type checking is only decidable if you are willing to annotate all kinds of subexpressions with their type (The annotations in the forall parts above are only a hint of what that would entail.).
This options seems to be overkill if all you want to achieve is polyadicity, though.
Disclaimer: My knowledge on type theory is a bit dated.