How do you print inside a case statement in SML? - sml

I'm just starting out with SML, and I'm trying to modify some code so I understand what it's doing (I can't find a decent SML/NJ debugger, but that's a separate question).
fun type_check e theta env non_gens =
case e of
constant_int _ => (integer, theta)
| constant_bool _ => (boolean, theta)
| ...
Assume this is valid code in that constant_int is part of a datatype already declared, etc. How do I add a print statement to say 'Returning "integer"' to the case? I tried:
...
constant_int _ => (print "returning integer") (integer, theta)
...
But I get:
stdIn:167.22-167.65 Error: operator is not a function [tycon mismatch]
operator: unit
in expression:
(print "returning integer") (integer,theta)
I think I'm just not understanding how to execute a sequence of statements, only the last of which should be treated as the return value. Any advice?
Also, how would I print my own datatype value? SML didn't like when I tried to pass a datatype value into print() so I probably have to create a new print function for each datatype, is that correct?

You can "execute a sequence of statements, only the last of which should be treated as the return value" by using semicolons.
...
constant_int _ => ( print "returning integer"; (integer,theta) )
...
In this case, we needed to wrap the sequence of statements in parentheses, because the semicolon has lower precedence than the case-expression, and so if we didn't have the parentheses, it would think that the case-expression ended at the semicolon, and that the entire case-expression is a part of the sequence, which is not what you want in this case.

Related

Ocaml Conversion String to int to char

I need to implement this function somewhere
String.get: string -> int -> char
I have tried this one but it does not seem to work
let String.get = fun x -> char_of_int(int_of_string x) ;;
The error I get is:
let String.get = fun x -> char_of_int(int_of_string x) ;;
^^^
Error: Syntax error
String.get is a syntax to denote the function get in module String. The syntax can not be used to (re)define a function as you wrote.
The function is documented here:
val get : string -> int -> char
String.get s n returns the character at index n in string s. You can also write s.[n] instead of String.get s n.
Raise Invalid_argument if n not a valid index in s.
What you are trying to implement is different, you are trying to read, from the string, an integer, and then convert it to a digit char (?)
Depending on what your actual requirements are, you might be asked to reimplement String.get on your own, so for example you would pick a different name in your current module (for now, this is sufficient, you don't need to bother about modules):
let char_at s n = ...
Or maybe you do actually need to convert from an integer. Please clarify your question.

Alert deprecated: Stdlib.String.set

The following code returns an error and says that the syntax is deprecated. What is the correct way to change a character in a string?
let hello = "Hello!" ;;
hello.[1] <- 'a' ;;
Alert deprecated: Stdlib.String.set
Use Bytes.set instead.
Error: This expression has type string but an expression was expected of type
bytes
Strings are immutable (or at least soon they will be), so you can't change their contents. You can, of course, create a copy of a string with the one character different, e.g.,
let with_nth_char m c =
String.mapi (fun i b -> if i = m then c else b)
and
# with_nth_char 1 'E' "hello";;
- : string = "hEllo"
But if you need to change characters in an array then you shouldn't use the string data type but instead rely on bytes which is a type for mutable strings. You can use Bytes.of_strings and Bytes.to_string to translate strings to bytes and vice verse.

expression expected type unit, but it already does

let _ =
try ("hello"; ()) with
| _ -> print_endline "hi"
Compiling this tells me that ("hello"; ()) 'should have type unit'
In fact, I get the same warning with this code
let _ = "hello"; ()
or this code
let _ = ("hello"; ())
But it does have type unit ... doesn't it?
The expression :
let f = "hello";1;;
Triggers the warning :
this expression should have type unit - around "hello" string.
This is because you are trying to return a first value via "hello", and then you return 1 meaning that ocaml must disregard "hello".
if you replace it by unit - meaning "here I return nothing", it will be ok.
The expression :
let f = (); 1;;
raises no warning and f is an int.
So the warning you are getting is related to the inner code of your expression, not to the type of the expression you have written.
let f = "hello";();;
The compiler warns you that you compute something that you disregard after that ("hello" is never used, and the return value is of f is ()). But, as you have noted, f has type unit.
In utop :
let _ = try ("hello"; ()) with
| _ -> print_endline "hi";;
You get :
Characters 13-20:
Warning 10: this expression should have type unit.
which locates exactly to the position of "hello" string - but does not locate to ("hello"; ()). ("hello"; ()) has type unit, exactly like print_endline "hi".
The warning is just about the fact that the expression that should be instead of "hello"; is expected to have type unit.

Shorthand If/Else statement with two statements inside IF

Sorry, I couldn't find a better fitting title, feel free to edit the title if you find a more suthing one. Here is my question, I know I can create a small version of IF/ELSE statement like this:
(condiction) ? numFound = true : numFound = false;
but, is there a way of having two statements inside the first condition, ex.
(condition) ? numFound = true, break: numFound = false;
normal version of if/else statement I want to write
if (condition)
{
numFound = true;
break;
}
else
numFound = false;
Sorry for the noob question, and thanks for the help!
In short, it isn't possible. The Ternary operator requires the operands to evaluate to a value, and code blocks don't. Comma expressions don't work, because they will set the value to the last one executed- break doesn't evaluate to a value. Additionally, break isn't a function to be evaluated, it's a statement.
The advice is to not use conditionals/ternary operators when you are doing things more complex than their base use- they're harder to parse by humans and any decent compiler will compile x = condition ? this:that the same as if(condition){x=this}else{x=that} (or optimize both to the same assembly).
No you cannot do that. The "small version" of the if/else is called the conditional operator. It is the only operator in c++ taking three operands and commonly also simply called "the ternary operator". From here:
Exp1 ? Exp2 : Exp3;
where Exp1, Exp2, and Exp3 are expressions. Notice the use and
placement of the colon. The value of a ? expression is determined like
this: Exp1 is evaluated. If it is true, then Exp2 is evaluated and
becomes the value of the entire ? expression. If Exp1 is false, then
Exp3 is evaluated and its value becomes the value of the expression.
And for some clarification what is an expression see this question. break is not an expression, but a statement, hence you cannot use it inside a ternary.
Anyhow I would advise you not to hide the break within more stuff in a single line. In a loop a break is something extremely important and it makes sense to make it stand out from the "normal" buissness that happens inside the loop. If I dont immediately see a break (or a return) in a loop then I assume that it does its full iteration. Overlooking a break can cause mayor confusion and misunderstanding.
You could use comma expressions. A comma expression of the form (expr1, expr2) evaluates expr1 (and ignores the value to which it evaluates) and then expr2, which's value is then the result of the overall comma expression.
int main(int argc, char* argv[]) {
bool r = (argc==1) ? (printf("no parameters"),true) : (printf("parameters"),false);
return 0;
}
My friend you're in luck. Use comma operator:
(condition) ? numFound=true, x=1, y=2: numFound = false;
Of course if you're specific to break; it won't work.
Your break doesn't work here but the task itself works. But be careful! Strange things can happen. See these examples:
0?printf("One"),printf("One"):printf("Two"),printf("Two"); /* TwoTwo */
0?(printf("One"),printf("One")):(printf("Two"),printf("Two")); /* TwoTwo */
1?printf("One"),printf("One"):printf("Two"),printf("Two"); /* OneOneTwo (!) */
1?(printf("One"),printf("One")):(printf("Two"),printf("Two")); /* OneOne */
This happens because of the comma operator which evaluates an expression fomr left to right and returns the value of the second statement for the whole expression.
The next step is to check the binding precedence of (), ?: and ,. We find here that the opertators are ordered from strong to weak like
()
?:
,
Therefore the third example I posted is evaluated as follows:
1?printf("One"),printf("One"):printf("Two"),printf("Two")
-> (1?printf("One"),printf("One"):printf("Two")),printf("Two")
-> (printf("One"),printf("One")),printf("Two")
-> OneOneTwo
I do really not recommend using the so called ternary operator in more complicated cases. Stick to clear code. You know "Code is read more than it is written."

Binding a variable to one of two values with IF?

In the following SPARQL query, I'm not sure how to use if to bind one of two strings to the variable ?result. I heard that there are concepts of “in scope” and “out of scope,” but I don't really see the difference. I've also tried putting the if clause in the select line, but it didn't work either. How can I fix this query to bind ?result to one of the two strings based on the condition?
SELECT ?result
WHERE{
?chain rdf:type rdfs:Property .
?chain rdfs:domain <http://www.vs.cs.hs-rm.de/ontostor/SVC#MDiskGroup> .
?chain rdfs:range <http://www.vs.cs.hs-rm.de/ontostor/SVC#IOgroup> .
?this ?chain ?arg .
?arg io:id ?var .
IF(?var = "0"^^xsd:integer,
BIND(" *"^^xsd:string AS ?result),
BIND(""^^xsd:string AS ?result)) .
}
The if operator in SPARQL isn't a statement as it sometimes is in a programming language, but rather is an "function form" for creating an expression (with special evaluation semantics). The value of if(test,a,b) is a if test is true, and b if test is false. As the documentation says:
17.4.1.2 IF
rdfTerm IF (expression1, expression2, expression3)
The IF function form evaluates the first argument, interprets it as a
effective boolean value, then returns the value of expression2 if the
EBV is true, otherwise it returns the value of expression3. Only one
of expression2 and expression3 is evaluated. If evaluating the first
argument raises an error, then an error is raised for the evaluation
of the IF expression.
Examples: Suppose ?x = 2, ?z = 0 and ?y is not bound in some query
solution:
IF(?x = 2, "yes", "no") returns "yes"
IF(bound(?y), "yes", "no") returns "no"
IF(?x=2, "yes", 1/?z) returns "yes", the expression 1/?z is not evaluated
IF(?x=1, "yes", 1/?z) raises an error
IF("2" > 1, "yes", "no") raises an error
So, if isn't a statement like it might be in a programming language, but it's simply a function (though lazily evaluated) that takes three arguments and returns a value. SPARQL is a query language, and doesn't have statements that get executed; it's a query language for matching patterns in a graph and binding variables to values. So if is a function, and it just so happens that if the first argument is true, then it returns the second argument, otherwise it returns the third. In general, you'd bind the value of a function to a variable with
bind( function(args...) as ?variable )
and this case is no different. You'd call the if function and bind its result to a variable with
bind( if(condition,then,else) as ?result )
In your case, this means that you would use the following query. I've added some newlines to help the readability, but they're not necessary. Integers in a SPARQL query are shorthand for a literal with type xsd:integer, so I've also used (thanks to RobV's comment) 0 instead of "0"^^xsd:integer. (See 2.3.2 Matching Literals with Numeric Types.)
bind(if(?var = 0,
" *"^^xsd:string,
""^^xsd:string )
as ?result)
If we actually want to shorten this even more, then we can use xsd:string as a constructor, and do (see 17.5 XPath Constructor Functions):
bind(xsd:string(if(?var = 0," *", "")) as ?result)
This might seem a little bit odd at first if you're used to doing things like
String result;
if ( var == 0 ) {
result = "case 1";
}
else {
result = "case 2";
}
but many language actually provide a ternary operator that lets you do the much shorter
String result = (var == 0) ? "case 1" : "case 2";
instead. This is the functionality you're getting with SPARQL.