In my code I call the validateFEN function with a FEN String. A Fen string looks like this for example:
",w84,w41,w56,w170,w56,w41,w84,/,,w24,w40,w17,w40,w48,,/,,,w16,w16,w16,,,/,,,,,,,,/,,,,,,,,/,,,,,,,,/,,,b1,b1,b1,,,/,,b3,b130,b17,b130,b129,,/,b69,b146,b131,b170,b131,b146,b69,"
The function should take the string and check if it's a FEN string.
How does it know if it's a FEN string? -> My string has 9 rows and 9 columns. I don't need to check if the pieces (example: w86) are at their right position.
validateFEN' b = help3 (filter (\x -> x == ',' || x == '/' ) b)
help3 b = (if help1 b == True then (if head (drop 8 b) == '/' then help3 (drop 9 b) else False) else False )
help1 b = help2 (take 8 b)
help2 b = foldr (+) 0 (map (\x -> if x == ',' then 1 else 0 )b) == 8
Why do I keep getting the error for a empty list?
Exception: Prelude.head: empty list
I understand that with my code there is no stop. The program doesn't know when the string is "correct".
Is there a shorter simpler way of doing this?
One way to reuse existing library functions to make this clearer would be to use stripPrefix.
help3 s = case stripPrefix ",,,,,,,,/" s of
Nothing -> False
Just s' -> help3 s'
Of course, you still need to handle the final case, where there is no terminating /. This can be done with a single extra clause:
help3 ",,,,,,,," = True
help3 s = {- ... -}
You might want to ponder whether validateFEN' should have a similar special case for the empty string.
BUT I would strongly suggest simply not implementing validateFEN' in the first place. My guess is that the plan is something like this:
Check if a string is valid FEN.
Process the string, assuming FEN-ness.
Instead, I recommend the following approach:
Parse the string into a native data structure that represents the information available in a FEN string.
Process the native structure.
Step 1, if written with standard parsing solutions, will "accidentally" validate the string -- i.e. running your parser will return something like Either Error FEN, which you can pattern match on to either discover that the string is invalid or that it is valid and has been turned into a more idiomatic representation.
I am new to SML. I tried to create and test the following function below, but I received an error. I do not know what is the problem.
fun isOld(pFirstTuple: int*int*int, pSecondTuple: int*int*int) =
if (#1 pFirstTuple) < (#1 pSecondTuple)
then
true
if (#1 pFirstTuple) = (#1 pSecondTuple)
then
if (#2 pFirstTuple) < (#2 pSecondTuple)
then
true
else
false
I have tried this command "val p = isOld((8,9,10),(10,11,12))", but it showed me the following error Unbound variable or constructor. How do I fix this?
Here's what your code looks like, stripped down by ignoring various subexpressions (replacing them with A, B, and C)
if A
then true
if B
then if C
then true
else false
You're making extensive use of if/then/else, but the syntax is not quite correct. In SML, every if must have both a then and else clause associated with it. Here's my guess at what you actually meant:
if A
then true
else if B
then if C
then true
else false
else false
This is starting to get quite messy---but you can clean it up with boolean logic. Notice, for example, that if X then true else false means exactly the same thing as simply writing X, because both expressions are type bool and will always evaluate to the same boolean, regardless of what X is. You can extend this reasoning to see that
if X then true else Y is equivalent to X orelse Y.
if X then Y else false is equivalent to X andalso Y.
With these ideas, we can clean up your code considerably:
A orelse (B andalso C)
How can multiple conditions be specified under single if? For example, consider the following java code snippet:
if(a==1 && a>b){
//statements ;
}
How can above code be written in sml? I know that I can achieve the goal by using two if's but still if there is a method to specify in the way I want, then it will be smooth.
SML's equivalent of && is andalso. For || there is orelse:
if a = 1 andalso a > b
then (* ... *)
else (* ... *)
Why is this Ocaml statement giving me a syntax error?
let a = 0;; if a = 0 then let b = 0;;
Do if then else statements always have to return a value?
EDIT: Here is the code I am struggling with. I want to apply this function over a list with the map function. The function is supposed to look at each word in the list wordlist and add to the stringmap. If it has already been added to the string map then add 1 to its password.
module StringMap = Map.Make(String)
let wordcount = StringMap.empty
let findword testword =
let wordcount = (if (StringMap.mem testword wordcount)
then (StringMap.add testword ((StringMap.find testword wordcount)+1) wordcount)
else (StringMap.add testword 1 wordcount))
List.map findword wordlist
You can only have an if then without else if the then expression evaluates to unit () Otherwise, the expression will not type check. An if without an else is equivalent to writing if x then y else () which can only type check if y is unit.
Check this out for a reference.
(Terminology note: there are no statements in OCaml because everything is an expression, so the term "if statement" doesn't quite apply. I still understood what you meant, but I thought this was worth noting)
Yes, if is an expression in OCaml, not a statement. The best way to look at it is that there are no statements in OCaml. Everything is an expression. (Admittedly there are expressions that return (), which are similar to statements.)
You can only have if b then e if the type of e is unit (i.e., if it returns ()).
Note also that you can't just say let v = e, except at the top level of a module. At the top level it defines a global name in the module. In other cases you need to say let v = e1 in e2; the let defines a local symbol v for use in the expression e2.
One answer to the let b = problem - it works like this:
let a = 0
let b = if a = 0 then 0 else 1
(* or whatever value you need in the else branch *)
And then the Map problem: the manual says Map is applicative - that means Stringmap.add returns a new map. You must use a ref to store your map - see this ocaml toplevel protocol:
# module StringMap = Map.Make(String);;
# let mymap = ref StringMap.empty ;;
val mymap : '_a StringMap.t ref = {contents = <abstr>}
# mymap := StringMap.add "high" 1 !mymap;;
- : unit = ()
# StringMap.mem "high" !mymap;;
- : bool = true
# StringMap.mem "nono" !mymap;;
- : bool = false
# StringMap.find "high" !mymap;;
- : int = 1
# StringMap.find "nono" !mymap;;
Exception: Not_found.
I have to write a code that takes integer list and writes them to a file. At the same time it returns true if the element is written, else false if it is not written.
I wrote something like
fun writetofile([],sfile)= false
|writetofile((l:int)::ls, sfile)=
let
val outs=TextIO.openOut(sfile)
fun writeinline(outs,[])=(false;TextIO.closeOut(outs))
|writeinline(outs,(l:int)::ls)=(true;TextIO.output(outs,(Int.toString(l)^"\n"));writeinline(outs,ls))
in
writeinline(outs,l::ls) before
TextIO.closeOut(outs)
end
;
I got following error:
Error: right-hand-side of clause doesn't agree with function result type [tycon mismatch]
expression: unit
result type: bool
in declaration:
writeNums =
(fn (nil,sfile) => true
| (:: <pat>,sfile) =>
let val <binding>
val <binding> in (<exp>; <exp>) end)
The body of a function must have the type specified in the function-result type constraint.
The base case of writetofile has type bool while the inductive case has type unit due to TextIO.closeOut(outs); so they don't agree on a return type for the function.
If you would like to return bool in the inductive case, you need something like TextIO.closeOut(outs); true.
By the way, your writeinline function always return unit so you don't need unused false, true values. Here is a corrected version:
fun writetofile([], sfile) = false
| writetofile((l:int)::ls, sfile) =
let
val outs = TextIO.openOut(sfile)
fun writeinline(outs,[]) = TextIO.closeOut(outs)
| writeinline(outs, l::ls)= ( TextIO.output(outs (Int.toString(l)^"\n"));
writeinline(outs, ls) )
in
( writeinline(outs, l::ls);
TextIO.closeOut(outs);
true )
end