How can I solve this Ocaml dictionary problem? - ocaml

I have to write a function that has as parameters a dictionary and a character. The dictionary is string to string and you should look at it as a function. For example f("a")="b" in ("a", "b"). The function returns a max number for which f^number(character) is defined and an exception if f(character) cycles at infinity.
so if I have for eg this dictionary [("a", "b");("b", "c");("d", "e");("e", "f");("f", "e")]
my function appelead with this dictionary and charcater 'a' will give the result 2(a goes in b, b goes is c and it stops); for 'x' it will give 0 beacuse there's no such key; for 'b' the result will be 1(b goes in c and stops); for 'd' it will raise an exception(d goes in e, e goes in f, f goes in e and returns in e so infinite cycle); same exception for 'e' or 'f'
module MS = Map.Make(String);;
let d = MS.add "a" "b" (MS.add "b" "c" (MS.add "d" "e" (MS.add "e" "f" (MS.add "f" "e" MS.empty))));;
let f d c =
I just created the dictionary because I don't have any idea how could I implement this problem, but I think I need MS.Fold function for going through the dictionary.

The purpose of a fold is to "visit" all the elements of a structure, while accumulating some desired result. Your goal isn't to visit all the elements of your dictionary (which secretly is a graph). So a fold probably isn't what you want.
I'd say your main problem is in detecting cycles so you can raise an exception. To do this you need to track the places you've been. Then you raise the exception when you come to a place for the second time.
Otherwise this is a standard graph traversal problem, I'd say. You can solve it with a recursive function that visits nodes (i.e., looks up strings in the dictionary) until it gets a resolution. A resolution is a string that isn't in the dictionary, or a visit to a string that has already been visited.
Update
OK, I'll write some code that shows how to move through the dictionary. This function returns a string that is the concatenation of the first 10 strings it encounters. If it reaches a dead end before 10 it returns what it has seen so far. It uses your module MS.
let what_i_saw dict str =
let rec look sofar n s =
if n <= 0 then
sofar
else
match MS.find_opt s dict with
| None -> sofar
| Some s2 -> look (sofar ^ s2) (n - 1) s2
in
look str 9 str
Here's how it looks when you call the function:
# what_i_saw d "d";;
- : MS.key = "defefefefe"
# what_i_saw d "a";;
- : MS.key = "abc"
By the way, you say your function takes a character but your dictionary has keys that are strings. Strings and characters aren't the same thing in OCaml. I'm using strings everywhere in this example.

Related

How can I improve my Haskell code and make it work?

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.

Ocaml: Get a list of characters that are between two characters

to clarify my dilemma I'll explain the problem I'm faced with...
Basically, I am being passed a string that can contain single characters or ranges of characters and am trying to return back a list of characters represented by the string I was passed.
Ex. "b" would just give a list ['b'] "a-z" would give ['a' ; 'b' ; 'c' ; ... ; 'z'] and something like "ad-g2-6" would be ['a' ; 'd' ; 'e' ; 'f' ; 'g' ; '2' ; '3' ; '4' ; '5' ; '6'] since there is the character a and the ranges d-g and 2-6. (Also worth noting that something like "a-" would just be ['a' ; '-'] since the range wasn't completed.
My ideas for solving this have come to exploding the string into a list of characters (lst) then pattern matching and building onto an accumulator like
let mainfunc str = let lst = (explode str) in
let rec func lst acc = match lst with
| [] -> acc
| a::'-'::b::t -> func t (acc # **SOMETHING TO GET THIS RANGE**)
| a::t -> func t (acc # [a])
in func lst []
Anything that could help me get a range between the characters would be great and I'm open to ideas if someone has a better way to go about this problem than what I have set up.
(Also note that my explode function works as intended and converts a string into a char list)
Since you wrote a successful explode function I'll assume that you have no trouble with recursion etc. So the problem might just be a way to talk about characters as values (so you can get the next character after a given one).
For this you can use Char.code and Char.chr (from the OCaml standard library).
Here's a function that takes a character and returns a list consisting of the character and the next one in order:
let char_pair c =
[ c; Char.chr (Char.code c + 1) ]
Here's how it looks when you run it:
# char_pair 'x';;
- : char list = ['x'; 'y']
(I leave as an exercise the problem of dealing with the character with code 255.)
As a side comment, your approach looks pretty good to me. It looks like it will work.

Getting elements from a list by an index list

I have two lists in Haskell.
Original list containing string values:
["Hello", "HELLO", "", "WORLD", "xxx", "world"]
Index list containing integer values where the strings are all upper case in the original list:
[1,3]
I incremented all the values in the index list with a function I created and make index2 list, overall it looks like this:
My code:
import Data.List
import Data.Char
import Data.Maybe
main = do
contents <- readFile "h.txt"
let original = lines (contents)
let allUpper = lines (map toUpper contents)
let onlyUpper = filter(/="") (intersect original allUpper)
let upperIndex = findIndices ('elem' onlyUpper) original
let index2 = (map increment upperIndex)
print index2
increment :: Int -> Int
increment x = x+1
I have managed to came this far with the help of yours. However, since I am a beginner I do not seem to understand how iteration over lists works.
The thing I want to accomplish is to check whether the corresponding index values (in index2) are empty or not in the original list, if they are empty, I want to remove them in index2.
Filtering empty elements
The thing I want to accomplish is to check whether the corresponding
index values (in index2) are empty or not in the original list, if
they are empty, I want to remove them in index2.
The code already filters out empty elements! Look at the following line:
let onlyUpper = filter(/="") (intersect original allUpper)
This line does two things:
it keeps only elements which are constituted only with uppercase letters(intersect original allUpper),
it filters out empty elements (filter(/="")).
If by empty elements you mean strings which contains only space characters or nothing, you can use instead:
filter (all isSpace)
Iterating over lists
I do not seem to understand how iteration over lists works.
In Haskell, lists are single chained lists: each element contains a value and a reference to the next value.
Therefore lists are not indexed: the !! operator have to go through each element to access a specific element making lists completely inefficient when dealing with direct access.
When you’re submitting a list to a function, you simply give it the first element.
With these considerations, when you work on lists, you have to avoid accessing elements via their index.
The idea is to create functions which do their job on simple values and mapping them to list of elements. Take a look at the toUpper function:
toUpper :: Char -> Char
It takes a Char and returns its uppercased version (also a Char).
Haskell does not have a toUpper function which works on String, you have to use something like map or <$> to apply toUpper to a list of char (a String):
map toUpper "ab" -- "AB"
toUpper <$> "ab" -- "AB"
The idea is to have functions which does only one specific thing. Upercasing and iterating over a list are two different things. Does the toUpper function need to know the index of the element it will uppercase? No!
Iterating over a list with index
You may ask: but what if my function REALLY need to consider the index of the elements? (ie: for filtering out even or odd elements).
You have two way of considering it:
a List is not the type you need to work with. Maybe Data.Map, Data.IntMap or Data.Vector are better suited for the task (see these modules for more information),
you need to use an intermediate type which will hold the index.
For example:
let string = "abcde"
let indexedString = zip [1..] string
print indexedString -- [(1, 'a'), (2, 'b), (3, 'c), (4, 'd), (5, 'e)]
Note that this also solves your need of an increment function since the index is started at whatever value you want.
To go back to the original string, you write:
map snd indexedString -- "abcde"
You need to use the fst and snd functions to work with the intermediate type, or to use pattern matching:
filter (\x -> snd x == 'b') indexedString -- [(2, 'b')]
map (\(i,s) -> (i, toUpper s)) indexedString -- [(1,'A'),(2,'B'),(3,'C'),(4,'D'),(5,'E')]
Taking the index into account:
let string = "abcde"
indexedString = zip [1..] string
upperEven (i, c) | even i = (i, toUpper c)
| otherwise = (i, c)
print $ map upperEven indexedString -- [(1,'a'),(2,'B'),(3,'c'),(4,'D'),(5,'e')]
print $ map snd $ map upperEven indexedString -- "aBcDe"
Notes
The increment function already exists in Haskell, it’s called succ (it is also a more generic function which works on every types supporting the Enum class like Int, Char…)
Why not use words :: String -> [String] on the contents you get from a file? Using lines :: String -> [String] would be an alternative if you had one word per line.
Then if i get your problem right, you could write the following to solve your problem:
import Data.List (findIndices)
import Data.Char (isUpper)
allUpperOneBasedIndices :: String -> [Int]
allUpperOneBasedIndices = map succ . findIndices (all isUpper) . words

How to recursively ask for input, and return a list

I've been trying many different ways to do this in Haskell, and I can't for the life of me figure this out.
I want to get a list of names from the user, and if I know the length of the list (let's assume that is n), I want to prompt the user n times and ask for the i th item at the i'th time.
So far, I have this:
getinput a b
| a == b = []
| otherwise = input:getinput (a+1) b
where input = do
a <- getLine
return a
but I keep getting errors.
Strongly appreciate any help!
Problem with your code
The return type of input is IO String so you just can not append it to a list.
Similarly the return type of getinput (a+1) b is IO [String] and not just [String].
Here I have corrected your code
getinput a b | a == b = return []
| otherwise = do
i <- getLine
rest <- getinput (a+1) b
return (i:rest)
A better and more haskellish way
getinput2 n = sequence $ replicate n getLine
Satvik had a good answer, but your code is also 100% correct.
You can append an IO String to the beginning of a list, as long as all elements are of the same type -- so you end up with something that has the type [IO String]
All you need to do, with the code you've written, is apply it with sequence -- for example:
sequence $ getinput 0 4

What to use instead of a list comprehension

I'm just getting started with Haskell and finished a nice exercise to make a Caesar cipher.
One of the first steps was to make a function that will take a letter and turn it into a number. I know that chr and ord can do this already but part of the exercise was to write your own.
let2num c = head [ b | (a,b) <- zip ['a'..'z'] [0..25], a==c]
I'm new to the Haskell syntax and one of the first things I learned was list comprehensions, so that has become my hammer. I'm very curious though, what is another (likely better) way to write this function?
If you're curious the rest of the cipher is in a gist.
EDIT
I'm also interested in other ways to translate back from numbers to letters.
num2let d = head [ a | (a,b) <- zip ['a'..'z'] [0..25], b==(d `mod` 26)]
My solution:
import Data.List
let2num c = let (Just n) = elemIndex c ['a'..'z'] in n
Or:
import Data.List
import Data.Maybe
let2num c = fromJust $ elemIndex c ['a'..'z']
Or in pointless style:
import Data.List
import Data.Maybe
let2num = fromJust . (flip elemIndex) ['a'..'z']
The function elemIndex returns the index of the first element in the given list which is equal (by ==) to the query element, or Nothing if there is no such element.
The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing). Using Maybe is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error.
The function fromJust extracts the element out of a Just.
The reverse process:
num2let = (!!) ['a'..'z']
!! is a List index (subscript) operator, starting from 0. It is an instance of the more general Data.List.genericIndex, which takes an index of any integral type.
(!!) is partially applied here, which means it still needs one argument of type Int to yield the result (a value from the list whose index equals to Int value you pass to num2let).
“Caesar simply replaced each letter in the message by the letter three places further down the alphabet, wrapping around at the end of the alphabet.” We can simply write it in Haskell. In fact we can avoid let2num and num2let altogether.
So let's start with defining a table to map plain text alphabet to the cipher text alphabet:
cipher = let abc = ['a'..'z']
code = drop 3 abc ++ take 3 abc
in zip abc code
It will look like
[('a','d'),('b','e'),('c','f'),('d','g'), ... ]
Now we can encrypt a symbol, if we simply lookup the letter in this dictionary:
ghci> lookup 'a' cipher
Just 'd'
lookup returns a Maybe Char value, we need to convert it to simply a Char, and for this I use maybe function, using '?' for symbols which were not found in the cipher, and id (identity function = no changes) to found symbols:
ghci> maybe '?' id (lookup 'a' cipher)
'd'
Now we can write an encrypt function to encode just one symbol, it will leave missing characters, like a space, unencrypted:
encrypt c = maybe c id (lookup c cipher)
To encrypt an entire string:
ghci> map encrypt "haskell is fun"
"kdvnhoo lv ixq"
So we can put it all together:
encrypt c = maybe c id (lookup c cipher)
where
cipher = let abc = ['a'..'z']
code = drop 3 abc ++ take 3 abc
in zip abc code
For completeness, I think somebody should mention that list comprehensions are just a shortcut for writing stuff in the list monad. Your code transcribed is, roughly, this:
let2num c = head $ do (a,b) <- zip ['a'..'z'] [0..25]
if a == c then [b] else []
Not a very interesting example, but there you go.
Also, de-sugaring the do syntax, this is the same:
let2num c = head $ zip ['a'..'z'] [0..25] >>= \(a,b) -> if a == c then [b] else []
I'm not sure why you are opposed to the ord solution. List-based solutions perform unnecessary work (traversing a list). And they still are desugared into invocation of the enumFromTo, a method of the Enum class which allows to convert between Ints and Chars in the same way as ord/chr do. This is the lowest-level interface provided for Char type, so you hardly can "write your own" here (apart from doing boxing/unboxing yourself, but this is not a big joy).
I would go with the following:
import Data.Char
caesar :: Int -> Char -> Char
caesar n c = if isAlpha c
then chr (ord 'a' + (ord c - ord 'a' + n) `mod` 26)
else c
and map (caesar n) over the string with n the desired offset.