I want to create a union function for two images (created using lists of type string.) I have started by creating a unionList function that combines two lists.
unionList :: String -> String -> String
unionList xs ys = xs ++ foldl (flip delete) ys xs
This works but not how i want it too.
I want it to work like:
input = unionList [’ ’,’ ’,’X’,’X’,’ ’] [’X’,’ ’,’X’,’ ’,’X’]
output = "X XXX"
any ideas on how it's done to achieve this.
EDIT: I'm ultimately trying to create a union of two images.
image 1 = [" XX ", image 2 = ["XX XX", type Img = [String]
" X X ", " X ",
" XX "] "XX XX"]
^
examples
Input = (imgUnion (image 1) (image 2))
should give me the union of the two images.
imgUnion defined as
imgUnion :: Img -> Img -> Img
There are probably better ways to do this, but I had some fun trying out a couple of methods.
Pattern matching on list head item:
unionList1 :: String -> String -> String
unionList1 ('X':xs) ( _ :ys) = 'X' : unionList1 xs ys
unionList1 ( _ :xs) ('X':ys) = 'X' : unionList1 xs ys
unionList1 ( _ :xs) ( _ :ys) = ' ' : unionList1 xs ys
unionList1 _ _ = []
Guards!
unionList2 :: String -> String -> String
unionList2 (x:xs) (y:ys)
| x == ' ' = y : rest
| y == ' ' = x : rest
| otherwise = x : rest
where rest = unionList2 xs ys
unionList2 _ _ = []
And a solution as proposed with zipWith:
unionList3 :: String -> String -> String
unionList3 = zipWith (\x y -> if x /= ' ' then x else y)
You can then use one of these union functions on the image:
imgUnion :: [String] -> [String] -> [String]
imgUnion = zipWith unionList3
main :: IO ()
main = do
let img1 = [" XX ",
" X X ",
" XX "]
img2 = ["XX XX",
" X ",
"XX XX"]
mapM_ putStrLn (imgUnion img1 img2)
Gives as output:
XXXXX
XX X
XXXXX
Related
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
...
I'm trying to do removing space (" ") from a string without using the strip function. How to implement if 'head' == " " (space) in the program?
skipSpaces :: (Eq a) => [a] -> [a]
skipSpaces [] = []
skipSpaces (h:t)
| h `elem` " " = skipSpaces t -- condition if 'head' is equal to " "(space),do nothing.
| otherwise = h : skipSpaces t -- produce the result
I don't know how to declare aboutif 'head' == " " (space)
nor if 'head' == "(contain_strings)"(a collection of letters)".
Example:
Input: "I am twenty one"
Output Expectation: "Iamtwentyone"
You can match the space directly:
skipSpaces [] = []
skipSpaces (' ':t) = skipSpaces t
skipSpaces (h:t) = h : skipSpaces t
One trick, though, is to think about what function to apply to skipSpaces t, depending on the value of h. Consider a slight modification of the above:
skipSpaces [] = []
skipSpaces (' ':t) = id (skipSpaces t)
skipSpaces (h:t) = (h :) (skipSpaces t)
Note the similarity between the last two cases. We can factor out the recursive call as follows:
skipSpaces [] = []
skipSpaces (h:t) = (if h == ' ' then id else (h :)) (skipSpaces t)
I could understand if the question doesn't really clarify my problem, so here is some more explanation:
I am trying to add the string "+" at the start of my string, which I get like this:
printLine :: [Int] -> String --Type of the function
printLine [] = "" --Base case
printLine (x:xs) = "+" ++ foldr (++) "+" f ++ printLine xs
where f = replicate x "-"
The result I get from the above:
+-----++------++------++------+
The result I would like to get:
+-----+------+------+------+
Basically my question is: How do I add "+" only at the start?
I can understand that this might be a silly question, but I am stuck for a while now and I can't find the answer on SO or elsewhere.
Proposal: don't detect when you're in the first iteration, which is hard; instead detect when you're in the last iteration, which is easy because it's the [] case in the first line.
printLine :: [Int] -> String
-- final iteration; add an extra + at the end
printLine [] = "+"
-- not the final iteration; don't include a + at the end of the -s
printLine (x:xs) = "+" ++ replicate x '-' ++ printLine xs
If an empty list must map to an empty string, one option is to fold with a special case for an empty list.
printLine :: [Int] -> String
printLine [] = ""
printLine xs = foldr (\x res -> '+' : replicate x '-' ++ res) "+" xs
So that
λ> map printLine [[], [1..4], [5]]
["","+-+--+---+----+","+-----+"]
Alternatively, since the original question asked for control during the first iteration, one option is to use a helper function. Here are two alternatives.
printLine' :: [Int] -> String
printLine' [] = ""
printLine' xs = '+' : go xs
where go :: [Int] -> String
go [] = ""
go (n:ns) = replicate n '-' ++ "+" ++ go ns
printLine'' :: [Int] -> String
printLine'' xs = go True xs
where go :: Bool -> [Int] -> String
go _ [] = ""
go isFirst (n:ns) = (if isFirst then "+" else "")
++ replicate n '-' ++ "+" ++ go False ns
With these definitions
λ> map printLine' [[], [1..4], [5]]
["","+-+--+---+----+","+-----+"]
λ> map printLine'' [[], [1..4], [5]]
["","+-+--+---+----+","+-----+"]
I need to count values inbetween values in a list i.e. [135,136,138,140] would count all the numbers between 135-136,136-138,138-140. with the input list [135.2,135.3,137,139] would out put[2,1,1] using type [Float] [Float] [Int]. So far I have:
heightbetween :: Float -> Float -> [Float] -> Int
heightbetween _ _ [] = 0
heightbetween n s (x:xs)
| (n < x) && (s > x) = 1 + (heightbetween n s xs)
| otherwise = heightbetween n s xs
count :: [Float] -> [Float] -> [Int]
count [] [] = []
count [x,y] = [(x,y)]
count (x:y:ys) = (x,y):count (y:ys)
forEach fun lst = heightbetween op ([],lst)
where
op (start,[]) = Nothing
op (start,a:as) = Just (start++(fun a):as
,(start++[a],as))
forPairs fun lst lst2 = map (map fst)
$ forEach (\(a,b)->(fun a b,b))
$ zip lst lst2
Your count looks strange. It should be like this:
-- count -> ranges -> data -> [counts]
count :: [Float] -> [Float] -> [Int]
count [] _ = [] -- no ranges given -> empty list
count [_] _ = [] -- no ranges, but single number -> empty list
count _ [] = [] -- no data given -> empty list
count (x:y:xs) d =
(heightbetween x y d) : count (y:xs) d
heightbetween :: Float -> Float -> [Float] -> Int
heightbetween _ _ [] = 0
heightbetween n s (x:xs)
| (n < x) && (s > x) = 1 + (heightbetween n s xs)
| otherwise = heightbetween n s xs
The other lines are obsolete.
Then invoking
count [135,136,138,140] [135.2,135.3,137,139]
gives
[2,1,1]
First, make sure that your range list is in order....
rangePoints = [135,136,138,140]
orderedRangePoints = sort rangePoints
Next, you will find it much easier to work with actual ranges (which you can represent using a 2-tuple (low,high))
ranges = zip orderedRangePoints $ tail orderedRangePoints
You will need an inRange function (one already exists in Data.Ix, but unfortunately it includes the upperbound, so you can't use it)
inRange (low,high) val | val >= low && val < high = True
inRange _ _ = False
You will also want to order your input points
theData = sort [135.2,135.3,137,139]
With all of this out of the way, the binCount function is easy to write.
binCount'::[(Float, Float)]->[Float]->[Int]
binCount' [] [] = []
binCount' (range:rest) vals =
length valsInRange:binCount' rest valsAboveRange
where
(valsInRange, valsAboveRange) = span (`inRange` range) vals
Notice, that I defined a function called binCount', not binCount. I did this, because I consider this an unsafe function, because it only works on ordered ranges and values.... You should finalize this by writing a safer binCount function, which puts all of the stuff above in its where clause. You should probably add all the types and some error checking also (what happens if a value is outside of all ranges?).
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.