I am working on a simulation for a checkers game currently. I have developed a function called onemove:
onemove :: (Int,[Char],[[Char]],(Int,Int)) -> (Int,[Char],[[Char]])
This function takes a tuple as input and returns a tuple of modified information. I have defined the input variables as follows:
onemove (a,b,c,(d,e))
Where c is a list of chars, ie, captured pieces. I am currently utilizing guards and a where clause to complete the move to be made from 'd' to 'e'. How do I append an element to the list b within the where clause, if even possible? My sample code is as follows:
onemove :: (Int,[Char],[[Char]],(Int,Int)) -> (Int,[Char],[[Char]])
onemove (a,b,c,(d,e))
| e <= 0 =(a-30,b,c)
| (posFrom == 'r') && (posTo == '-') && ( leftOrRight == 9) = (a-15,b,removeWRightMan)
| otherwise = (10000,b,c)
where posFrom = getPos d c
rightWGuy = d+4
b ++ rightWGuy
removeWRightMan = setPos rightWGuy sFPosTo '-'
The value rightWGuy is however an Int and I am attempting to pass it to a [char]..Does this need to be converted to a char before attepting to append to the list b? Thanks
Well to just convert rightWGuy to a [Char] you could do:
import Data.Char (intToDigit)
-- some other things
b ++ [(intToDigit rightWGuy)]
Note that intToDigit only works for input in range [0..15]!
Alternatively, to simplify you can also just use show. Another advantage of show is that it supports any number, not only 0 to 15.
b ++ (show rightWGuy)
With the clarification of your comment, you probably want to so this:
onemove :: (Int,[Char],[[Char]],(Int,Int)) -> (Int,[Char],[[Char]])
onemove (a,b,c,(d,e))
| e <= 0 =(a-30,b,c)
| (posFrom == 'r') && (posTo == '-') && ( leftOrRight == 9) = (a-15,x,removeWRightMan) -- instead of b use x now
| otherwise = (10000,b,c)
where
posFrom = getPos d c
rightWGuy = d+4
x = b ++ (show rightWGuy) -- x is now b ++ rightWGuy
removeWRightMan = setPos rightWGuy sFPosTo '-'
Because Haskell has no side effects, just doing b ++ [(intToDigit rightWGuy)] will not change b, it will yield a new list which is the result of the concatenation. This result we now store in x, which we will use in our new tuple as you wish to do.
Related
I need to process a string using foldr where '#' means deleting the previous character. For example:
>backspace "abc#d##c"
"ac"
>backspace "#####"
""
It needs to be done using foldr through one pass of the list, without using reverse and/or (++).
Here what I have got so far:
backspace :: String -> String
backspace xs = foldr func [] xs where
func c cs | c /= '#' = c:cs
| otherwise = cs
But it just filter the '#' from the string. I thought about deleting the last element of current answer every time c == '#' and got something like that
backspace :: String -> String
backspace xs = foldr func [] xs where
func c cs | c /= '#' = c:cs
| cs /= [] = init cs
| otherwise = cs
but it is not working properly,
ghci> backspace "abc#d##c"
"abc"
You can use (Int, String) as state for your foldr where the first Int is the number of backspaces, and the String is the current string constructed.
This thus means that you can work with:
backspace :: String -> String
backspace = snd . foldr func (0, [])
where func '#' (n, cs) = (n+1, cs)
func c (n, cs)
| n > 0 = … -- (1)
| otherwise = … -- (2)
In case we have a character that is not a #, but n > 0 it means we need to remove that character, and thus ignore c and decrement n. In case n == 0 we can add c to the String.
I leave filling in the … parts as an exercise.
My goal is to take a char list like:
['a'; 'a'; 'a'; 'a'; 'a'; 'b'; 'b'; 'b'; 'a'; 'd'; 'd'; 'd'; 'd']
Count the number of repeated characters and transform it into a (int * char) list like this:
[(5, 'a'); (3, 'b'); (1, 'a'); (4, 'd')]
I am completely lost and also am very very new to OCaml. Here is the code I have rn:
let to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
let count = int 0 in
while t <> [] do
if h = t then
count := count + 1;
done;
I am struggling on how to check the list like you would an array in C or Python. I am not allowed to use fold functions or map or anything like that.
Edit: Updated code, yielding an exception on List.nth:
let rec to_run_length (lst : char list) : (int * char) list =
let n = ref 0 in
match lst with
| [] -> []
| h :: t ->
if h = List.nth t 0 then n := !n + 1 ;
(!n, h) :: to_run_length t ;;
Edit: Added nested match resulting in a function that doesn't work... but no errors!
let rec to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
match to_run_length t with
| [] -> []
| (n, c) :: tail ->
if h <> c then to_run_length t
else (n + 1, c) :: tail ;;
Final Edit: Finally got the code running perfect!
let rec to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
match to_run_length t with
| (n, c) :: tail when h = c -> (n + 1, h) :: tail
| tail -> (1, h) :: tail ;;
One way to answer your question is to point out that a list in OCaml isn't like an array in C or Python. There is no (constant-time) way to index an OCaml list like you can an array.
If you want to code in an imperative style, you can treat an OCaml list like a list in C, i.e., a linked structure that can be traversed in one direction from beginning to end.
To make this work you would indeed have a while statement that continues only as long as the list is non-empty. At each step you examine the head of the list and update your output accordingly. Then replace the list with the tail of the list.
For this you would want to use references for holding the input and output. (As a side comment, where you have int 0 you almost certainly wanted ref 0. I.e., you want to use a reference. There is no predefined OCaml function or operator named int.)
However, the usual reason to study OCaml is to learn functional style. In that case you should be thinking of a recursive function that will compute the value you want.
For that you need a base case and a way to reduce a non-base case to a smaller case that can be solved recursively. A pretty good base case is an empty list. The desired output for this input is (presumably) also an empty list.
Now assume (by recursion hypothesis) you have a function that works, and you are given a non-empty list. You can call your function on the tail of the list, and it (by hypothesis) gives you a run-length encoded version of the tail. What do you need to do to this result to add one more character to the front? That's what you would have to figure out.
Update
Your code is getting closer, as you say.
You need to ask yourself how to add a new character to the beginning of the encoded value. In your code you have this, for example:
. . .
match to_run_length t with
| [] -> []
. . .
This says to return an empty encoding if the tail is empty. But that doesn't make sense. You know for a fact that there's a character in the input (namely, h). You should be returning some kind of result that includes h.
In general if the returned list starts with h, you want to add 1 to the count of the first group. Otherwise you want to add a new group to the front of the returned list.
I am new to SML and don't understand too about the syntax.
I am doing a practice on checking palindrome without reversing the list. Here is my code
fun symmetric(i,n,inlist) =
if List.nth(inlist,i-1) = List.nth(inlist,n-i)
then true
else
false;
fun palindrome(n, inlist) =
let
val i = ref 1
in
while !i < n do (
if symmetric(!i,!n,!inlist) = false
then false
else ()
i := !i + 1
)
true
end;
I got errors in fun palindrome only, but can't fix it by myself.
You can even make a palindrome checker without converting your string to a list:
fun palindrome s =
let fun check i j =
i >= j orelse
String.sub (s, i) = String.sub (s, j) andalso
check (i+1) (i-1)
in check 0 (String.size s - 1) end
Here is some feedback for your code:
Naturally, consider using recursion rather than iteration.
A common problem for non-functional programmers is that they seem to want to execute many statements in succession only for their side-effect. In functional programming you rely very much on the value of every expression to guide the result of the program. There is a ; operator, though, and it could be used like this:
fun palindrome s =
let val i = ref 0
val j = ref (String.size s - 1)
val result = ref true
in while !i < !j do
(if String.sub (s, !i) = String.sub (s, !j)
then (i := !i + 1 ; j := !j - 1)
else (i := !j ; result := false))
; !result
end
Often, though, if you want to do multiple things in a row, let-expressions are just as neat as the ; operator.
The code
if A = false
then false
else B
can be written as
if not (A)
then false
else B
which can further be improved into
if A
then B
else false
which is really the same as
A andalso B
So the morals are:
Instead of A = false, write not A (and instead of A = true, write A).
You can always replace if ... then <true/false> else <true/false> with some combination of andalso and orelse. That is, if-then-else is never necessary when the result type is bool (but you might still prefer it if the logic is very convoluted).
If the restriction against reversing a list was intended to ban using the built-in rev but not computations which implicitly reverse lists, here is a stack-based approach. The idea is to push characters onto a stack (represented as a list), and then pop them off, checking them against the original list of characters. If either the stack or the original list empty first, or if the item popped doesn't match the corresponding char in the original list -- it isn't a plalindrome
fun pushAll [] stack = stack
| pushAll (x::xs) stack = pushAll xs (x::stack)
fun popCheck [] [] = true
| popCheck [] _ = false
| popCheck _ [] = false
| popCheck (x::xs) (y::ys) = x = y andalso popCheck xs ys
fun palindrome s =
let val chars = explode s
val stack = pushAll chars []
in
popCheck chars stack
end;
I have a character list [#"h", #"i", #" ", #"h", #"i"] which I want to get the first word from this (the first character sequence before each space).
I've written a function which gives me this warning:
stdIn:13.1-13.42 Warning: type vars not generalized because of value
restriction are instantiated to dummy types (X1,X2,...)
Here is my code:
fun next [] = ([], [])
| next (hd::tl) = if(not(ord(hd) >= 97 andalso ord(hd) <= 122)) then ([], (hd::tl))
else
let
fun getword [] = [] | getword (hd::tl) = if(ord(hd) >= 97 andalso ord(hd) <= 122) then [hd]#getword tl else [];
in
next (getword (hd::tl))
end;
EDIT:
Expected input and output
next [#"h", #"i", #" ", #"h", #"i"] => ([#"h", #"i"], [#" ", #"h", #"i"])
Can anybody help me with this solution? Thanks!
This functionality already exists within the standard library:
val nexts = String.tokens Char.isSpace
val nexts_test = nexts "hi hi hi" = ["hi", "hi", "hi"]
But if you were to build such a function anyway, it seems that you return ([], []) sometimes and a single list at other times. Normally in a recursive function, you can build the result by doing e.g. c :: recursive_f cs, but this is assuming your function returns a single list. If, instead, it returns a tuple, you suddenly have to unpack this tuple using e.g. pattern matching in a let-expression:
let val (x, y) = recursive_f cs
in (c :: x, y + ...) end
Or you could use an extra argument inside a helper function (since the extra argument would change the type of the function) to store the word you're extracting, instead. A consequence of doing that is that you end up with the word in reverse and have to reverse it back when you're done recursing.
fun isLegal c = ord c >= 97 andalso ord c <= 122 (* Only lowercase ASCII letters *)
(* But why not use one of the following:
fun isLegal c = Char.isAlpha c
fun isLegal c = not (Char.isSpace c) *)
fun next input =
let fun extract (c::cs) word =
if isLegal c
then extract cs (c::word)
else (rev word, c::cs)
| extract [] word = (rev word, [])
in extract input [] end
val next_test_1 =
let val (w, r) = next (explode "hello world")
in (implode w, implode r) = ("hello", " world")
end
val next_test_2 = next [] = ([], [])
when trying to define a function that would remove the largest subset of set m that is also a subset of set a from set a, I encountered the following error:
filename.hs:7:33:parse error (possibly incorrect indentation)
for the following code:
exclude :: Integral t => [t] -> [t] -> [t]
a `exclude` m
| m == [] = a
| a == (b ++ c) = b
| otherwise = []
where b /= []
where c = [z | z <- m]
how do I implement multiple conditions/definitions (using where or otherwise), or correct the function to properly work in a different way?
One part of your question is easily answerable. You can have multiple definitions in one where clause, as in
foo n
| even r = bar
| s < 12 = baz
| otherwise = quux
where
r = n `mod` 1357
h = a + b
where
(a,b) = r `divMod` 53 -- nested where-clause
s = r - 3*h
and you can have nested where-clauses. But in a where-clause, you can only have definitions. Conditions would go into the guards (or if then else expressions on the right hand side) and can be combined with the boolean operators, (&&), (||), not ...
As for your code, so far I haven't figured out what you intended it to do.
Saying "the largest subset of set m that is also a subset of set a"
is the same as saying "all elements of m that are also elements of a".
Then the solution to your problem is stated simply as:
exclude a = filter (`notElem` a)
which when applied to m will give you a subset of m modulo any elements
that are also members of a. That is, it will "remove the largest subset of
m that is also a subset of a".
In fact,there is a function in Data.List and Data.Set called '\'. I'll show '\' function of Data.List .
import Data.List
exclude :: Integral t => [t] -> [t] -> [t]
a `exclude` m = a\\m