Haskell Function - string

I need to create a function that takes string and decoding rules. It is supposed to change characters in string until there is nothing possible to change according to decoding rules.
Each time I get string and decoding rules (first is what change, second is to what).
I'm quite lost, I tried to create all possible combinations and then generate list based on rules. Here's my try.
rules = [('E',"GZ"),('F',"HK"),('C',"EF"),('J',"CC")]
string = "JCEJ"
combinations = [(x,y,z) | x <- [ch | ch <- string], y <- [x | (x,y) <- rules], z <- [y | (x,y) <- rules]]
generate = [z | (x,y,z) <- combinations, if x == y then z else x]
Error message:
decoder.hs:8:57: error:
• Couldn't match expected type ‘Bool’ with actual type ‘[Char]’
• In the expression: z
In the expression: if x == y then z else x
In a stmt of a list comprehension: if x == y then z else x
|
8 | generate = [z | (x,y,z) <- combinations, if x == y then z else x]
| ^
decoder.hs:8:64: error:
• Couldn't match expected type ‘Bool’ with actual type ‘Char’
• In the expression: x
In the expression: if x == y then z else x
In a stmt of a list comprehension: if x == y then z else x
|
8 | generate = [z | (x,y,z) <- combinations, if x == y then z else x]
| ^

Disclaimer: none of this is as pretty as it could be.
You have a lookup table with rules. Haskell has a handy lookup function:
ghci> :t lookup
lookup :: Eq a => a -> [(a, b)] -> Maybe b
We can fold a lookup over the string:
ghci> foldr (\x i -> case lookup x rules of {Just s -> s ++ i; _ -> (x:i)}) "" "EF"
"GZHK"
Let's call this singlePassDecode:
singlePassDecode :: Foldable t => t Char -> [(Char, [Char])] -> [Char]
singlePassDecode s rules = foldr update "" s
where
update ch acc =
case lookup ch rules of
Just s' -> s' ++ acc
Nothing -> ch : ""
But a single pass doesn't necessarily get the job done. We need to recursively call this until there are no transformations left to perform. This means we need to know if any of the characters in the input string are in the lookup table.
The ... is left to fill in with the correct recursive call to avoid presenting a complete answer.
decode :: [Char] -> [(Char, [Char])] -> [Char]
decode s rules
| any (\ch -> elem ch (map fst rules)) s = ...
| otherwise = s
The first condition might also be expressed as follows.
any (flip elem $ map fst rules) s

A String is a list of Chars, so the [ch | ch <- string] is not necessary.
You here defined some inner list comprehensions with x, but that x is a more locally scoped variable, not the x as the x in x <- [ ch | ch <- str].
You can make a filter condition to filter, so:
generate = concat [ y | x <- string, (x', y) <- rules, … ]
Here the … is a part that you will need to fill in. It will need to compare x with x'.

Your list of rules describes a mapping from one Char to either two Chars (if there is a match) or one Char (the original input, if there is no match). We can handle both of those cases by always returning a [Char], and we can generalize to any a rather than being specific to Char:
import Data.Maybe (fromMaybe)
transform :: Eq a => [(a, [a])] -> a -> [a]
transform rules x = fromMaybe [x] (lookup x rules)
Since this mapping depends on no other context, concatMap (also spelled (>>=)) is a great tool for applying it across a list of inputs and concatenating the results.
transformAll :: Eq a => [(a, [a])] -> [a] -> [a]
transformAll rules = concatMap (transform rules)
-- or, transformAll = concatMap . transform
It will also be useful to have a function that applies a function repeatedly until it results in no change:
fixPoint :: Eq a => (a -> a) -> a -> a
fixPoint f x | x == x' = x
| otherwise = fixPoint f x'
where x' = f x
Then all that's left is to combine our tools:
transformStringRepeatedly :: Eq a => [(a, [a])] -> [a] -> [a]
transformStringRepeatedly rules = fixPoint (transformAll rules)
-- or, transformStringRepeatedly = fixPoint . transformAll
main = print (transformStringRepeatedly [('E',"GZ"),('F',"HK"),('C',"EF"),('J',"CC")] "JCEJ")
We can see that it produces the answer you expected:
$ runghc tmp.hs
"GZHKGZHKGZHKGZGZHKGZHK"

Related

Haskell Expected type: [t0 a0] Actual type: [a]

data PossibleTuple a = Multiple (a, Int) | Single a
pack :: (Eq a) => [a] -> [a]
{-
...
-}
encode_modified' :: (Eq a) => [a] -> [PossibleTuple a]
encode_modified' [] = []
encode_modified' x = map (\x -> element x) (pack x)
where
element x
| length x > 1 = Multiple (x, length x)
| otherwise = Single x
I'm trying to do this:
encodeModified "aaaabccaadeeee"
[Multiple 4 'a',Single 'b',Multiple 2 'c',
Multiple 2 'a',Single 'd',Multiple 4 'e']
but I get this error:
* Couldn't match type `a' with `t0 a0'
`a' is a rigid type variable bound by
the type signature for:
encode_modified' :: forall a. Eq a => [a] -> [PossibleTuple a]
at src/Lib.hs:117:1-54
Expected type: [t0 a0]
Actual type: [a]
* In the second argument of `map', namely `(pack x)'
In the expression: map (\ x -> element x) (pack x)
In an equation for encode_modified':
encode_modified' x
= map (\ x -> element x) (pack x)
where
element x
| length x > 1 = Multiple (x, length x)
| otherwise = Single x
* Relevant bindings include
x :: [a] (bound at src/Lib.hs:119:18)
encode_modified' :: [a] -> [PossibleTuple a]
(bound at src/Lib.hs:118:1)
|
119 | encode_modified' x = map (\x -> element x) (pack x)
| ^^^^^^
Why would pack x need to have the type t0 a0? x is of type a0 and thus pack x would have type [a0].
All the types seem to match. The output of the map function is PossibleTuple a0. I don't even know where the a0 t0 comes from.
What type do you suppose element has? You call length on its argument, meaning you think it takes a list as input. However, you also map it over a list of type [a], meaning you think it can take any type a as input. This is a type mismatch.
Similarly you say you hope that your result will look like [Multiple (4, 'a')], but your element function can never produce this result. The first element in each tuple is the length of the second element, and length 'a' is a type error.
The first thing I would do is re-examine the type of pack, though. It can't do anything with its current type that seems very relevant. Probably it should be Eq a => [a] -> [[a]]. After that you will have more type errors to resolve, leading to a better definition of element.
Multiple 4 'a'
This does not match the value constructor you defined. This is the constructor you defined
data PossibleTuple a = Multiple (a, Int) | Single a
So to construct Multiple, you should do Multiple ('a', 4). Conversely, if you want to do Multiple 4 'a', then your constructor should read
data PossibleTuple a = Multiple Int a | Single a
It should be pack :: Eq a => [a] -> [[a]].
This function already exists, it is called group. It groups together consecutive elements of a list, which are equal to one another.
Then element needs just a small tweak to work,
where
element x
| length x > 1 = Multiple (.... x, length x)
| otherwise = Single (.... x)
with the same name appearing on both ....s. Normally using that function is frowned upon but here it will be correct by construction.
Or you could use # patterns in pattern matching, like
where
element x#(h:_)
...........
This encoding is known as run-length encoding, in case you were wondering.
To easier see what's going on, it usually helps mentally if we name the lists by variables in plural, like using xs for a list of xs (xs is to be read like it rhymes with "axes"):
encode_modified' :: (Eq a) => [a] -> [PossibleTuple a]
encode_modified' [] = []
encode_modified' x = -- map (\x -> element x) (pack x)
map (\xs -> element xs) (pack x)
where
element xs
-- | length x > 1 = Multiple (x, length x) -- length of "x"??
| length xs > 1 = Multiple ( x , length xs) -- no, of "xs"!!
---
| otherwise = Single x
-----
and the (underscored) plurality type mis-matches are now self-evident.

Haskell type mismatch Int and [Int]

I'm a beginner to Haskell. I'm trying to create a function which has two parameters: a character and a string.
This function is supposed to go through the string and check if the character given is in the string, and then return a list of integers representing the position of the characters in the string.
My code is:
tegnPose :: Char -> String -> [Int]
tegnPose c [] = []
tegnPose c (x:xs) = [if not (xs !! a == c)
then [a] ++ tegnPose c xs
else tegnPose c xs |a <- [0.. length xs - 1]]
Which is a recursive function with list comprehension.
The error I get:
Uke4.hs:14:7: error:
* Couldn't match expected type `Int' with actual type `[Int]'
* In the expression: [a] ++ tegnPose c xs
In the expression:
if not (xs !! a == c) then [a] ++ tegnPose c xs else tegnPose c xs
In the expression:
[if not (xs !! a == c) then
[a] ++ tegnPose c xs
else
tegnPose c xs |
a <- [0 .. length xs - 1]]
|
14 | then [a] ++ tegnPose c xs
| ^^^^^^^^^^^^^^^^^^^^
Uke4.hs:15:7: error:
* Couldn't match expected type `Int' with actual type `[Int]'
* In the expression: tegnPose c xs
In the expression:
if not (xs !! a == c) then [a] ++ tegnPose c xs else tegnPose c xs
In the expression:
[if not (xs !! a == c) then
[a] ++ tegnPose c xs
else
tegnPose c xs |
a <- [0 .. length xs - 1]]
|
15 | else tegnPose c xs |a <- [0.. length xs - 1]]
I don't understand how the mismatch happens, as the recursive function should just run through.
Here's why the mismatch happens. First, note that a list comprehension that returns a list of type [a] must generate elements of type a, so you need the following to match:
example :: [Int]
-- .-- the final value is "[Int]"
-- |
example = [ 2+x*y | x <- [1..10], y <- [1..5], x < y]
-- ^^^^^
-- |
-- `- therefore, this must be "Int"
In your example, the type signature for tegnPose implies that the list comprehension must return an [Int], but the expression generating list elements, namely:
if ... then [a] ++ tegnPose c xs else tegnPose c cx
is clearly not returning a plain Int the way it's supposed to.
The first error message is indicating that actual type of the subexpression [a] ++ tegnPos c xs which is [Int] does not match the expected type of the result of the entire if .. then .. else expression which should have type Int.
If I understand your question correctly (i.e., return a list of the integer positions of each occurrence of a character in a string so that tegnPose 'a' "abracadabra" returns [0,3,5,7,10], then you should either use recursion or a list comprehension, but not both.
Note that the non-recursive list comprehension:
tegnPose c xs = [a | a <- [0..length xs - 1]
almost does what you want. All that's missing is testing the condition to see if the character at position a is a c. If you don't know about using "guards" in list comprehensions, go look it up.
Alternatively, the recursive function without a list comprehension:
tegnPose c (x:xs) = if (x == c) then ??? : tegnPose c xs
else tegnPose c xs
tegnPose _ [] = []
also almost does what you want, except it's not obvious what to put in place of ??? to return a number indicating the current position. If you write a recursive version with an extra parameter:
tp n c (x:xs) = if (x == c) then n : tp (???) c xs
else tp (???) c xs
tp _ _ [] = []
with the idea that you could define:
tegnPose c xs = tp 0 c xs
then you'd be closer, if only you could figure out what new value for n should go in place of the ???.
More standard Haskell solutions might involve things like zips:
> zip [0..] "abracadabra"
[(0,'a'),(1,'b'),(2,'r'),...]
and filters:
> filter (\(i,c) -> c == 'a') $ zip [0..] "abracadabra"
[(0,'a'),(3,'a'),...]
and maps:
> map fst $ filter (\(i,c) -> c == 'a') $ zip [0..] "abracadabra"
[0,3,5,7,10]
or looking in Data.List for a function that does what you want:
> elemIndices 'a' "abracadabra"
[0,3,5,7,10]
Just for some variety a simpler way of implementing this functionality with a single foldr could be;
import Data.Bool (bool)
charIndices :: Char -> String -> [Int]
charIndices c = foldr (\t r -> bool r (fst t : r) (snd t == c)) [] . zip [0..]
*Main> charIndices 't' "tektronix test and measurement instruments"
[0,3,10,13,29,34,40]
Explanation:
Type of foldr is Foldable t => (a -> b -> b) -> b -> t a -> b
It takes three parameters;
A function which accepts two parameters
An initial value of type b
A traversable data type which hold values of type a
an returns a single value of type b.
In this particular case our type a value is Char type, which makes t a a String type (due to type signature) and type b value is a list of integers [Int].
The provided function as the first parameter is (\t r -> bool r (fst t : r) (snd t == c)) which is very simple if you check Data.bool. bool is a ternary operator of type a -> a -> Bool -> a which takes three arguments. In order they are negative result, positive result and condition. (negative is on the left as usual in Haskell). It checks if the current character is equal to our target character c, if so it returns fst t : r if not r (r means result). And finally t is the current tuple of the fed tuples list. The tuples list is constructed by zip [0..] s where s is not shown in the function definition due to partial application.

Haskell Replace a value in a list with another value

I am pretty new to Haskell. I am trying to write a program that takes two values and a list and replaces every instance of the first value in the list with the second. E.g. repOcc 'n' 'i' "pink" would return "piik".
The following is my code:
repOcc :: t -> t -> [t] -> [t]
repOcc x y (z:zs) = if z == x
then z = y
subst x y zs
else subst x y zs
The error I am receiving at compile time is:
rev.hs:3 :32: error:
parse error on input '='
Perhaps you need a 'let' in a 'do' block?
e.g. 'let x = 5' instead of 'x = 5'
Failed, modules loaded: none.
Your program looks rather "imperative" whereas Haskell aims to be more "declarative". So you can not set a variable z in a list: once a list is constructed, you can not alter it anymore. So you have to construct a new list where elements that are equal to x are set to y.
Next you make use of the (==) function. That function is defined in the Eq typeclass, so you need to add Eq t as a type constraint to the signature.
So now we can start to construct such function. Usually when working with a list, we make use of recursion. The base case of the recursion is usually the empty list. In case we encounter the empty list, we should return an empty list, regardless what x and y are. So we use underscores as "don't care" patterns, and use [] as the list pattern, and write:
repOcc _ _ [] = []
The recursive case is when the list contains a head h and a tail t in a (h:t) pattern. In that case we check whether h is equal to x. In case it is, we construct a list with y as head, otherwise h is still the head.
repOcc x y (h:t) | x == h = y : tl
| otherwise = h : tl
Now the question remains what the tail of the result list tl should be. Here we use recursion, so we call repOcc with x y t:
where tl = repOcc x y t
Or putting it together:
repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc _ _ [] = []
repOcc x y (h:t) | x == h = y : tl
| otherwise = h : tl
where tl = repOcc x y t
We can write such recursive functions, but the above is actually a special case of a map function: we map every character in such way that we check whether it is equal to x and if it is, we return y, otherwise we return h. So we can rewrite the above as:
repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc x y ls = map (\h -> if h == x then y else h) ls
We can further improve the code by making use of eta-reduction:
repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc x y = map (\h -> if h == x then y else h)

How I can set the signature of a function right?

I'm practicing some Haskell to understand the \, case.. of and Maybe better.
I've got this little function here which should return Nothing if the array is empty, Just y if y is equal to the head of the array xs and Just (tail xs) if y is not equal to the head of the array xs.
I set the return type of the function to Maybe a because in one case it should return an Int and in the other an [Int].
funct :: Int -> [Int] -> Maybe a
funct = \y xs -> case xs of
[] -> Nothing
xs -> if ((head xs) == y)
then Just y
else Just (tail xs)
What am I missing? I am getting the error that it couldn't match type a with [Int]. Isn't the a in Maybe a generic or is it influenced by the fact that I "used" the a as an Int in the Just y part?
EDIT: Ok my suggestion was bs, I tested it with Just (tail xs) in the then and else part and I'm still getting the same error.
set the return type of the function to Maybe a because in one case it should return an Int and in the other an [Int].
Haskell is statically typed. Meaning it can not - at runtime - have a different return type. It can only have one return type. a is not an ad hoc type (in the sense that it can be any type at runtime). It means that a will be determined - at compile time - based on the types of other parameters.
For instance you can write: foo :: a -> a -> a to specify that if foo takes two Ints (again known at compile time), the result will be an Int.
You can however use Either a b to say that you will either return a Left a, or a Right b. So you can rewrite it to:
funct :: Int -> [Int] -> Maybe (Either Int [Int])
funct = \y xs -> case xs of
[] -> Nothing
xs -> if ((head xs) == y)
then Just (Left y)
else Just (Right (tail xs))
Your function however is quite verbose, you can make it more clear and compact as follows:
funct :: Int -> [Int] -> Maybe (Either Int [Int])
funct _ [] = Nothing
funct y (h:t) | h == y = Just (Left y)
| otherwise = Just (Right t)
Furthermore we can generalize it to:
funct :: Eq a => a -> [a] -> Maybe (Either a [a])
funct _ [] = Nothing
funct y (h:t) | h == y = Just (Left y)
| otherwise = Just (Right t)
Here Eq is a typeclass that specifies that there exists a function (==) :: a -> a -> Bool that we can use. Otherwise using == in the body of the function would not be possible.
Furthermore we use patterns in the head of every clause. [] is a pattern that describes the empty list. (h:t) on the other hand is a pattern describing a list containing at least one element: the head h, followed by a (possibly empty tail t).

Having trouble with H-15

I am doing Problem 15. Which states:
(**) Replicate the elements of a list a given number of times.
Example:
* (repli '(a b c) 3)
(A A A B B B C C C)
Example in Haskell:
> repli "abc" 3
"aaabbbccc"
My plan was to do something like this:
repli :: [a] -> Integer -> [a]
repli [] y = []
repli (x:xs) y | appendNo x y == [] = repli(xs) y
| otherwise = appendNo x y : (x:xs)
where
appendNo :: a -> Integer -> [a]
appendNo a 0 = []
appendNo a y = a:appendNo a (y-1)
Where I would make a function called appendNo that returns a list of 1 element y times then append it to the original list. Then take the body of the list and repeat this process until there are no more body elements left. But, I get the error:
H15.hs:6:30:
Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for repli :: [a] -> Integer -> [a] at H15.hs:3:1
In the return type of a call of `appendNo'
In the first argument of `(:)', namely `appendNo x y'
In the expression: appendNo x y : (x : xs)
Failed, modules loaded: none.
6:30 is at the on the p in appendNo in this line:
| otherwise = appendNo x y : (x:xs)
Ok thanks dave4420 I was able to figure it out by doing:
repli :: [a] -> Integer -> [a]
repli [] y = []
repli (x:xs) y = appendNo x y ++ repli(xs) y
where
appendNo :: a -> Integer -> [a]
appendNo a 0 = []
appendNo a y = a:appendNo a (y-1)
| otherwise = appendNo x y : (x:xs)
There is a type error in this line. So ask yourself:
What is the type of appendNo x y?
What is the type of (x:xs)?
What is the type of (:)?
Then you should be able to see why they don't match up.
If you still can't see why they don't match up, ask yourself
What is the type of x?
What is the type of xs?
What is the type of (:)?
Bear in mind that this time the types do match up.
As the problem is solved, let me give you a hint: You should try to think in transformations, not in "loops". Start with some concrete values like n = 3 and list = "ABCD". Then you should think along the lines "I need every element three times". There is already a function for doing the replication, which is surprisingly called replicate. So the sentence can be translated to map (replicate 3) "ABCD", which gives you ["AAA","BBB","CCC","DDD"]. That's almost what you want, you just need to concat the elements. This gives:
repli list n = concat (map (replicate n) list)
Because this operation is very common, there is a concatMap function combining concat and map, as well as the operator (>>=) doing the same, just with flipped arguments. So a very short solution would be:
repli list n = list >>= replicate n
This can be translated to the do-notation or a list comprehension as well:
repli list n = do
x <- list
y <- replicate n x
return y
repli list n = [y | x <- list, y <- replicate n x]

Resources