Swapping 2 characters in list of strings (Haskell) - string

I need to swap blank space with letter from "moves" and each time I swap it I need to continue with another one from moves. I get Couldn't match expected type, even though I just want to return value x when it doesn't meet condition.
Error message:
[1 of 1] Compiling Main ( puzzlesh.hs, interpreted )
puzzlesh.hs:19:43: error:
• Couldn't match expected type ‘Int -> a’ with actual type ‘Char’
• In the expression: x
In the expression: if x == ' ' then repl x else x
In an equation for ‘eval’: eval x = if x == ' ' then repl x else x
• Relevant bindings include
eval :: Char -> Int -> a (bound at puzzlesh.hs:19:5)
repl :: forall p. p -> Int -> a (bound at puzzlesh.hs:20:5)
moves :: [a] (bound at puzzlesh.hs:16:9)
p :: t [Char] -> [a] -> [Int -> a] (bound at puzzlesh.hs:16:1)
|
19 | eval x = if x == ' ' then repl x else x
| ^
Failed, no modules loaded.
Code:
import Data.Char ( intToDigit )
sample :: [String]
sample = ["AC DE",
"FBHIJ",
"KGLNO",
"PQMRS",
"UVWXT"]
moves = "CBGLMRST"
type Result = [String]
pp :: Result -> IO ()
pp x = putStr (concat (map (++"\n") x))
p input moves = [eval x | x <- (concat input)]
where
c = 1
eval x = if x == ' ' then repl x else x
repl x count = moves !! count
count c = c + 1
I need to take character from moves, replace it onto blank space and do this till moves is []
Desired output:
ABCDE
FGHIJ
KLMNO
PQRST
UVWX

As with most problems, the key is to break it down into smaller problems. Your string that encodes character swaps: can we break that into pairs?
Yes, we just need to create a tuple from the first two elements in the list, and then add that to the result of calling pairs on the tail of the list.
pairs :: [a] -> [(a, a)]
pairs (x:tl#(y:_)) = (x, y) : pairs tl
pairs _ = []
If we try this with a string.
Prelude> pairs "CBGLMRST"
[('C','B'),('B','G'),('G','L'),('L','M'),('M','R'),('R','S'),('S','T')]
But you want a blank space swapped with the first character:
Prelude> pairs $ " " ++ "CBGLMRST"
[(' ','C'),('C','B'),('B','G'),('G','L'),('L','M'),('M','R'),('R','S'),('S','T')]
Now you have a lookup table with original characters and their replacements and the rest is straightforward. Just map a lookup on this table over each character in each string in the list.
Because you never touch any letter in the original strings more than once, you won't have to worry about double replacements.
Prelude> s = ["AC DE","FBHIJ","KGLNO","PQMRS","UVWXT"]
Prelude> r = "CBGLMRST"
Prelude> r' = " " ++ r
Prelude> p = pairs r'
Prelude> [[case lookup c p of {Just r -> r; _ -> c} | c <- s'] | s' <- s]
["ABCDE","FGHIJ","KLMNO","PQRST","UVWXT"]

Related

Need help in subproblem of parser for polynomials (Haskell)

I'm currently doing an assignment for college where we are implementing an polynomial calculator in Haskell.
The first part of the assignment is doing poly operations, and that is already done.
We get extra credit if we implement an parser for the polynomial, which I'm currently doing by turning a string to a tuple of [(factor, [(variable, exponent)])].
This means "-10y^4 - 5z^5" => "[(-10, [('y', 4)]), (-5, [('z', 5)].
The sub-problem I'm having trouble with is when I encounter polynomials like "5xy^2z^3" that should be stored as [(5, [('x',1), ('y', 2),('z',3)]], I don't know how to parse it.
Any suggestion on how I could approach this?
Thank you in advance for your help!
-- Slipts lists by chosen Char, only used with '+' in this project
split :: Char -> String -> [String]
split _ "" = []
split c s = firstWord : (split c rest)
where firstWord = takeWhile (/=c) s
rest = drop (length firstWord + 1) s
-- Remove all spaces from a string, for easier parsing
formatSpace :: String -> String
formatSpace = filter (not . isSpace)
-- Clever way to parse the polynomial, add an extra '+' before every '-'
-- so after we split the string by '+', it helps us keep the '-'
simplify_minus :: String -> String
simplify_minus [] = ""
simplify_minus (x:xs)
| x == '^' = x : head xs : simplify_minus (tail xs)
| x == '-' = "+-" ++ simplify_minus xs
| otherwise = x : simplify_minus xs
-- Splits an String by occurrences of '+' and creates a list of those sub-strings
remove_plus :: String -> [String]
remove_plus s = split '+' s
-- Removes multiplication on substrings
remove_mult :: [String] -> [[String]]
remove_mult [] = []
remove_mult (x:xs) = (remove_power (split '*' x)) : remove_mult xs
-- Function used to separate a variable that has an power. This translates ["y^2] to [["y", "2"]]
remove_power :: [String] -> [String]
remove_power [] = []
remove_power (x:xs) = (split '^' x) ++ remove_power xs
-- Wrapper function for all the functions necessary to the parser
parse_poly :: String -> [(Integer, String, Integer)]
parse_poly [] = []
parse_poly s = map (tuplify) (rem_m (remove_plus (simplify_minus (formatSpace s))))
rem_m :: [String] -> [String]
rem_m l = map (filter (not . (=='*'))) l
helper_int :: String -> Integer
helper_int s
| s == "" = 1
| s == "-" = -1
| otherwise = read s :: Integer
helper_char :: String -> String
helper_char s
| s == [] = " "
| otherwise = s
tuplify :: String -> (Integer, String, Integer)
tuplify l = (helper_int t1, helper_char t3, helper_int (drop 1 t4))
where (t1, t2) = (break (isAlpha) l)
(t3, t4) = (break (=='^') t2)
main :: IO()
main = do
putStr("\nRANDOM TESTING ON THE WAE\n")
putStr("--------------\n")
print(parse_poly "5*xyz^3 - 10*y^4 - 5*z^5 - x^2 - 5 - x")
-- [(5,"xyz",3),(-10,"y",4),(-5,"z",5),(-1,"x",2),(-5," ",1),(-1,"x",1)]
``
You have pretty much everything there already, but you do need to use break recursively to grab everything until the next variable. You probably should also use the similar span to first grab the coefficient.
parsePositiveMonomial :: String -> (Integer, [(Char, Integer)])
parsePositiveMonomial s = case span isDigit s of
([], varPows) -> (1, parseUnitMonomial varPows)
(coef, varPows) -> (read coef, parseUnitMonomial varPows)
where parseUnitMonomial [] = []
parseUnitMonomial (var:s') = case break isAlpha s' of
...

Haskell: Exception <<loop>> on recursive data entry

So I'm trying to make a little program that can take in data captured during an experiment, and for the most part I think I've figured out how to recursively take in data until the user signals there is no more, however upon termination of data taking haskell throws Exception: <<loop>> and I can't really figure out why. Here's the code:
readData :: (Num a, Read a) => [Point a] -> IO [Point a]
readData l = do putStr "Enter Point (x,y,<e>) or (d)one: "
entered <- getLine
if (entered == "d" || entered == "done")
then return l
else do let l = addPoint l entered
nl <- readData l
return nl
addPoint :: (Num a, Read a) => [Point a] -> String -> [Point a]
addPoint l s = l ++ [Point (dataList !! 0) (dataList !! 1) (dataList !! 2)]
where dataList = (map read $ checkInputData . splitOn "," $ s) :: (Read a) => [a]
checkInputData :: [String] -> [String]
checkInputData xs
| length xs < 2 = ["0","0","0"]
| length xs < 3 = (xs ++ ["0"])
| length xs == 3 = xs
| length xs > 3 = ["0","0","0"]
As far as I can tell, the exception is indication that there is an infinite loop somewhere, but I can't figure out why this is occurring. As far as I can tell when "done" is entered the current level should simply return l, the list it's given, which should then cascade up the previous iterations of the function.
Thanks for any help. (And yes, checkInputData will have proper error handling once I figure out how to do that.)
<<loop>> basically means GHC has detected an infinite loop caused by a value which depends immediately on itself (cf. this question, or this one for further technical details if you are curious). In this case, that is triggered by:
else do let l = addPoint l entered
This definition, which shadows the l you passed as an argument, defines l in terms of itself. You meant to write something like...
else do let l' = addPoint l entered
... which defines a new value, l', in terms of the original l.
As Carl points out, turning on -Wall (e.g. by passing it to GHC at the command line, or with :set -Wall in GHCi) would make GHC warn you about the shadowing:
<interactive>:171:33: warning: [-Wname-shadowing]
This binding for ‘l’ shadows the existing binding
bound at <interactive>:167:10
Also, as hightlighted by dfeuer, the whole do-block in the else branch can be replaced by:
readData (addPoint l entered)
As an unrelated suggestion, in this case it is a good idea to replace your uses of length and (!!) with pattern matching. For instance, checkInputData can be written as:
checkInputData :: [String] -> [String]
checkInputData xs = case xs of
[_,_] -> xs ++ ["0"]
[_,_,_] -> xs
_ -> ["0","0","0"]
addPoint, in its turn, might become:
addPoint :: (Num a, Read a) => [Point a] -> String -> [Point a]
addPoint l s = l ++ [Point x y z]
where [x,y,z] = (map read $ checkInputData . splitOn "," $ s) :: (Read a) => [a]
That becomes even neater if you change checkInputData so that it returns a (String, String, String) triple, which would better express the invariant that you are reading exactly three values.

Write the recursive function adjuster

Write the recursive function adjuster. Given a list of type
x, an int and an element of type x, either remove from the front of the
list until it is the same length as int, or append to the end of the list
until it is the same length as the value specified by the int.
expected:
adjuster [1..10] (-2) 2 -> *** Exception: Invalid Size
adjuster [1..10] 0 2 -> []
adjuster "apple" 10 ’b’ -> "applebbbbb"
adjuster "apple" 5 ’b’ -> "apple"
adjuster "apple" 2 ’b’ -> "le"
adjuster [] 3 (7,4) -> [(7,4),(7,4),(7,4)]
What i did:
adjuster (x:xs) count b
| count < 0 = error "Invalid Size"
| count == 0 = []
| count < length xs = adjuster xs (count-1) b
| otherwise = (adjuster xs (count-1) b):b
the error that I'm getting:
* Occurs check: cannot construct the infinite type: t ~ [t]
Expected type: [t]
Actual type: [[t]]
* In the expression: (adjuster xs (count - 1) b) : b
In an equation for `adjuster':
adjuster (x : xs) count b
| count < 0 = error "Invalid Size"
| count == 0 = []
| count < length xs = adjuster xs (count - 1) b
| otherwise = (adjuster xs (count - 1) b) : b
* Relevant bindings include
b :: [[t]] (bound at code01.hs:21:23)
adjuster :: [a] -> Int -> [[t]] -> [t] (bound at code01.hs:21:1)
I'm new in haskell.I'll really appreciate some help.
You are trying to construct a list within lists within lists and so on and so forth …
Why is this?
(:) :: a -> [a] -> [a]
The colon operator takes an element and a list of such elements as an argument and constructs a list from that (by prepending that element).
In your case if (adjuster ...) had type [a] then b must be of type [[a]], by line 4 which is the same as the end result, but line 3 says the type is [a] - which is different. This is what GHC tries to tell you.
How to fix it?
First of all, it is always a good advice to add a type signature to every top level function:
adjuster :: [a] -> Int -> a -> [a]
which should clean up your error-message and keep you honest, when implementing your function.
So how to fix this: - you could use b:adjuster xs (count-1) b but this would yield a result in the wrong order - so
choose a different operator: (++) and wrap the b inside a list.
| otherwise = (adjuster xs (count-1) b)++[b]
Now a few more hints:
turn on -Wall when you compile your file - this will show you that you missed the case of adjuster [] ...
using length is a relatively expensive operation - as it needs to traverse the full list to be calculated.
As an exercise - try to modify your function to not use length but only work with the base cases [] for list and 0 for count (here the function replicate might be helpful).
Here is another approach, without error handling
adjuster xs n v = tnr n $ (++) (replicate n v) $ tnr n xs
where tnr n r = take n $ reverse r
if you play with the signature, perhaps cleaner this way
adjuster n v = tnr . (++) (replicate n v) . tnr
where tnr = take n . reverse

how to replace a letter in string with Haskell

i have to make Haskell function called markDups that processes a string, replacing all repeated occurrences of a character with the underscore, "_", character.
here is my code i did so far.
makeBar :: Char -> [Char] -> [Char]
makeBar c (x:xs) | c == x = '_':makeBar c xs --turn into a "_"
| otherwise = x:makeBar c xs--ignore and move on
when I run this, here is my output with error message
output should be like this
what should I do?
This seems to work:
import Data.Set
main = putStrLn (markDups "hello world" empty)
markDups :: [Char] -> Set Char -> [Char]
markDups [] set = []
markDups (x:rest) set
| member x set = '_':(markDups rest set)
| otherwise = x:(markDups rest (insert x set))

Doing a binary search on some elements in Haskell

I'm trying to complete the last part of my Haskell homework and I'm stuck, my code so far:
data Entry = Entry (String, String)
class Lexico a where
(<!), (=!), (>!) :: a -> a -> Bool
instance Lexico Entry where
Entry (a,_) <! Entry (b,_) = a < b
Entry (a,_) =! Entry (b,_) = a == b
Entry (a,_) >! Entry (b,_) = a > b
entries :: [(String, String)]
entries = [("saves", "en vaut"), ("time", "temps"), ("in", "<`a>"),
("{", "{"), ("A", "Un"), ("}", "}"), ("stitch", "point"),
("nine.", "cent."), ("Zazie", "Zazie")]
build :: (String, String) -> Entry
build (a, b) = Entry (a, b)
diction :: [Entry]
diction = quiksrt (map build entries)
size :: [a] -> Integer
size [] = 0
size (x:xs) = 1+ size xs
quiksrt :: Lexico a => [a] -> [a]
quiksrt [] = []
quiksrt (x:xs)
|(size [y|y <- xs, y =! x]) > 0 = error "Duplicates not allowed."
|otherwise = quiksrt [y|y <- xs, y <! x]++ [x] ++ quiksrt [y|y <- xs, y >! x]
english :: String
english = "A stitch in time save nine."
show :: Entry -> String
show (Entry (a, b)) = "(" ++ Prelude.show a ++ ", " ++ Prelude.show b ++ ")"
showAll :: [Entry] -> String
showAll [] = []
showAll (x:xs) = Main.show x ++ "\n" ++ showAll xs
main :: IO ()
main = do putStr (showAll ( diction ))
The question asks:
Write a Haskell programs that takes
the English sentence 'english', looks
up each word in the English-French
dictionary using binary search,
performs word-for-word substitution,
assembles the French translation, and
prints it out.
The function 'quicksort' rejects
duplicate entries (with 'error'/abort)
so that there is precisely one French
definition for any English word. Test
'quicksort' with both the original
'raw_data' and after having added
'("saves", "sauve")' to 'raw_data'.
Here is a von Neumann late-stopping
version of binary search. Make a
literal transliteration into Haskell.
Immediately upon entry, the Haskell
version must verify the recursive
"loop invariant", terminating with
'error'/abort if it fails to hold. It
also terminates in the same fashion if
the English word is not found.
function binsearch (x : integer) : integer
local j, k, h : integer
j,k := 1,n
do j+1 <> k --->
h := (j+k) div 2
{a[j] <= x < a[k]} // loop invariant
if x < a[h] ---> k := h
| x >= a[h] ---> j := h
fi
od
{a[j] <= x < a[j+1]} // termination assertion
found := x = a[j]
if found ---> return j
| not found ---> return 0
fi
In the Haskell version
binsearch :: String -> Integer -> Integer -> Entry
as the constant dictionary 'a' of type
'[Entry]' is globally visible. Hint:
Make your string (English word) into
an 'Entry' immediately upon entering
'binsearch'.
The programming value of the
high-level data type 'Entry' is that,
if you can design these two functions
over the integers, it is trivial to
lift them to to operate over Entry's.
Anybody know how I'm supposed to go about my binarysearch function?
The instructor asks for a "literal transliteration", so use the same variable names, in the same order. But note some differences:
the given version takes only 1
parameter, the signature he gives
requires 3. Hmmm,
the given version is not recursive, but he asks for a
recursive version.
Another answer says to convert to an Array, but for such a small exercise (this is homework after all), I felt we could pretend that lists are direct access. I just took your diction::[Entry] and indexed into that. I did have to convert between Int and Integer in a few places.
Minor nit: You've got a typo in your english value (bs is a shortcut to binSearch I made):
*Main> map bs (words english)
[Entry ("A","Un"),Entry ("stitch","point"),Entry ("in","<`a>"),Entry ("time","te
mps"),*** Exception: Not found
*Main> map bs (words englishFixed)
[Entry ("A","Un"),Entry ("stitch","point"),Entry ("in","<`a>"),Entry ("time","te
mps"),Entry ("saves","en vaut"),Entry ("nine.","cent.")]
*Main>
A binary search needs random access, which is not possible on a list. So, the first thing to do would probably be to convert the list to an Array (with listArray), and do the search on it.
here's my code for just the English part of the question (I tested it and it works perfectly) :
module Main where
class Lex a where
(<!), (=!), (>!) :: a -> a -> Bool
data Entry = Entry String String
instance Lex Entry where
(Entry a _) <! (Entry b _) = a < b
(Entry a _) =! (Entry b _) = a == b
(Entry a _) >! (Entry b _) = a > b
-- at this point, three binary (infix) operators on values of type 'Entry'
-- have been defined
type Raw = (String, String)
raw_data :: [Raw]
raw_data = [("than a", "qu'un"), ("saves", "en vaut"), ("time", "temps"),
("in", "<`a>"), ("worse", "pire"), ("{", "{"), ("A", "Un"),
("}", "}"), ("stitch", "point"), ("crime;", "crime,"),
("a", "une"), ("nine.", "cent."), ("It's", "C'est"),
("Zazie", "Zazie"), ("cat", "chat"), ("it's", "c'est"),
("raisin", "raisin sec"), ("mistake.", "faute."),
("blueberry", "myrtille"), ("luck", "chance"),
("bad", "mauvais")]
cook :: Raw -> Entry
cook (x, y) = Entry x y
a :: [Entry]
a = map cook raw_data
quicksort :: Lex a => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = quicksort (filter (<! x) xs) ++ [x] ++ quicksort (filter (=! x) xs) ++ quicksort (filter (>! x) xs)
getfirst :: Entry -> String
getfirst (Entry x y) = x
getsecond :: Entry -> String
getsecond (Entry x y) = y
binarysearch :: String -> [Entry] -> Int -> Int -> String
binarysearch s e low high
| low > high = " NOT fOUND "
| getfirst ((e)!!(mid)) > s = binarysearch s (e) low (mid-1)
| getfirst ((e)!!(mid)) < s = binarysearch s (e) (mid+1) high
| otherwise = getsecond ((e)!!(mid))
where mid = (div (low+high) 2)
translator :: [String] -> [Entry] -> [String]
translator [] y = []
translator (x:xs) y = (binarysearch x y 0 ((length y)-1):translator xs y)
english :: String
english = "A stitch in time saves nine."
compute :: String -> [Entry] -> String
compute x y = unwords(translator (words (x)) y)
main = do
putStr (compute english (quicksort a))
An important Prelude operator is:
(!!) :: [a] -> Integer -> a
-- xs!!n returns the nth element of xs, starting at the left and
-- counting from 0.
Thus, [14,7,3]!!1 ~~> 7.

Resources