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.
Related
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"
I'm new to Haskell, I've to do a function that counts the number of vowels in a string using the higher order function foldr
I've tried to create this function
vowels [] = 0
vowels (x:xs)= if elem x "aeiou" then 1 + vowels xs else vowels xs
But it doesn't work and I'm not able to do it using foldr, any suggestion?
Well a foldr :: (a -> b -> b) -> b -> [a] -> b is a function where the first parameter is a function f :: a -> b -> b. You can here see the a parameter as the "head" of the list, the second parameter b as the result of the recursion with foldr, and you thus want to produce a result in terms of these two for the entire function. This logic is basically encapsulated in the second clause of your function.
Indeed:
vowels (x:xs) = if elem x "aeiou" then 1 + vowels xs else vowels xs
can be rewritten as:
vowels (x:xs) = if elem x "aeiou" then 1 + rec else rec
where rec = vowels xs
and rec is thus the outcome of the recursive call, the second parameter of the "fold"-function. x on the other hand is the first parameter of the "fold"-function. We thus need to write this function, only in terms of x and rec, and this is simply:
\x rec -> if elem x "aeiou" then 1 + rec else rec
Furthermore we need to handle the case of an empty list, this is the first clause of your function. In that case the result is 0, this is the second paramter of the foldr, so we got:
vowels = foldr (\x rec -> if elem x "aeiou" then 1 + rec else rec) 0
Or a more clean syntax:
vowels = foldr f 0
where f x rec | elem x "aeiou" = 1 + rec
| otherwise = rec
We can further clean it up, by abstracting away rec:
vowels = foldr f 0
where f x | elem x "aeiou" = (1+)
| otherwise = id
You need to take a look at foldr's signature.
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Never mind the Foldable part and focus on the first function it takes.
(a -> b -> b) b is the same type that you are supposed to return, so directly translating the signature into a lambda gives you \x acc -> acc, but you want to do more than just ignore every element.
Take a look at your function if elem x "aeiou" then 1 + vowels xs else vowels xs. You need to return b, not recurse adding one to it.
if elem x "aeiou" this part is fine. then 1 + acc <- see what I'm doing here? I'm adding one to the accumulator, not recursing manually, that is done by foldr, as for the else case: acc. That's it. You don't need to even touch x.
Putting it all together: vowels = foldr (\x acc -> if elem x "aeiou" then 1 + acc else acc) 0
The 0 is what the acc will start as.
If you want to know more about folds, I suggest you reimplement them yourself.
The easiest way to write something like that is to let the compiler guide you.
First, look only at the obvious parts of the foldr signature. This is the traditional signature, specialised to lists. Nowedays, foldr can actually work on any other suitable container as well, but this isn't important here.
foldr :: (a -> b -> b) -- ^ Not obvious
-> b -- ^ Not obvious
-> [a] -- ^ A list... that'll be the input string
-> b -- ^ Final result, so nothing to be done here.
So, your implementation will be of the form
vowels :: String -> Int
vowels s = foldr _ _ s
where we yet need to find out what to put in the _ gaps. The compiler will give you useful hints as to this:
$ ghc wtmpf-file6869.hs
[1 of 1] Compiling Main ( wtmpf-file6869.hs, wtmpf-file6869.o )
/tmp/wtmpf-file6869.hs:2:18: error:
• Found hole: _ :: Char -> Int -> Int
• In the first argument of ‘foldr’, namely ‘_’
In the expression: foldr _ _ s
In an equation for ‘Main.vowels’: Main.vowels s = foldr _ _ s
• Relevant bindings include
s :: String (bound at /tmp/wtmpf-file6869.hs:2:8)
vowels :: String -> Int (bound at /tmp/wtmpf-file6869.hs:2:1)
|
2 | vowels s = foldr _ _ s
| ^
So, a function that merely takes a single character, and then modifies an integer. That was actually already part of your original implementation:
vowels (x:xs) = if elem x "aeiou" then 1 + vowels xs else vowels xs
The bold part is essentially a function of a single character, that yields a number-modifier. So we can put that in the foldr implementation, using lambda syntax:
vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else _) _ s
I had to put the 1+ in parenthesis so it works without an explicit argument, as an operator section.
Ok, more gaps:
• Found hole: _ :: Int -> Int
• In the expression: _
In the expression: if x `elem` "aeiou" then (1 +) else _
In the first argument of ‘foldr’, namely
‘(\ x -> if x `elem` "aeiou" then (1 +) else _)’
• Relevant bindings include
x :: Char (bound at wtmpf-file6869.hs:2:20)
s :: String (bound at wtmpf-file6869.hs:2:8)
vowels :: String -> Int (bound at wtmpf-file6869.hs:2:1)
|
2 | vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else _) _ s
| ^
So that's the modifier that should take action when you've found a non-vowel. What do you want to modify in this case? Well, nothing actually: the count should stay as-is. That's accomplished by the id function.
vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else id) _ s
• Found hole: _ :: Int
• In the second argument of ‘foldr’, namely ‘_’
In the expression:
foldr (\ x -> if x `elem` "aeiou" then (1 +) else id) _ s
In an equation for ‘vowels’:
vowels s
= foldr (\ x -> if x `elem` "aeiou" then (1 +) else id) _ s
• Relevant bindings include
s :: String (bound at wtmpf-file6869.hs:2:8)
vowels :: String -> Int (bound at wtmpf-file6869.hs:2:1)
|
2 | vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else id) _ s
| ^
So that's an integer that's completely outside of the foldr. I.e. it can't depend on the string. In particular, it will also be used if the string is empty. Can only be 0!
vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else id) 0 s
No more gaps, so the compiler will just accept this. Test it:
$ ghci wtmpf-file6869
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Loaded GHCi configuration from /home/sagemuej/.ghci
[1 of 1] Compiling Main ( wtmpf-file6869.hs, interpreted )
Ok, 1 module loaded.
*Main> vowels "uwkaefdohinurheoi"
9
Your definition can be tweaked into
vowels [] = 0
vowels (x:xs) = g x (vowels xs)
where
g x rec = if elem x "aeiou" then 1 + rec else rec
which matches the pattern
foldr r z [] = z
foldr r z (x:xs) = r x (foldr r z xs)
if we have foldr r z = vowels and r = g, and also z = 0.
That "pattern" is in fact a valid definition of the foldr function.
Thus we indeed have
vowels xs = foldr g 0 xs
where
g x rec = if elem x "aeiou" then 1 + rec else rec
I'm trying to solve the 99 problems in Haskell, and for the 4th question, I have first tried such a solution
myLength :: [a] -> Int
myLength [] = 0
myLength ys = go 1 ys
where
go :: Int -> [a] -> Int
go n xs
| ( (take n xs) == (take (n+1) xs) ) = n
| otherwise = go (n+1) xs
However, the compiler gives the error:
Problem4.hs:10:8: error:
• No instance for (Eq a1) arising from a use of ‘==’
Possible fix:
add (Eq a1) to the context of
the type signature for:
go :: forall a1. Int -> [a1] -> Int
• In the expression: ((take n xs) == (take (n + 1) xs))
In a stmt of a pattern guard for
an equation for ‘go’:
((take n xs) == (take (n + 1) xs))
In an equation for ‘go’:
go n xs
| ((take n xs) == (take (n + 1) xs)) = n
| otherwise = go (n + 1) xs
|
10 | | ( (take n xs) == (take (n+1) xs) ) = n
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As far as I understood, the reason for the error it that when we try to compare the lists returned from (take n xs) and (take (n+1) xs), the compiler does not know the types of lists in advance, so it cannot compare them, and this is why it complains, so before this line, I need to tell the compiler that both return values are the same type, and the type is [a], but how can we do that ?
A confusion: when we specify the type signature of go, we are explicitly fixing the what is the type of xs, i.e so shouldn't the list that is return by the function take have the same type, namely [a], hence shouldn't the compiler be able to compare them ?
Edit:
Note that, I have another function in the definition of a function, and there are lots of things that are different from the question that is marked as duplicate, and as you can observe, the given answer to that question does not fully solves this question.
What you need is instance contexts (here Eq a), which is indicated by =>:
myLength :: Eq a => [a] -> Int
myLength [] = 0
myLength ys = go 1 ys
where
go :: Eq a => Int -> [a] -> Int
go n xs
| ( (take n xs) == (take (n+1) xs) ) = n
| otherwise = go (n+1) xs
But this is not a proper answer to the question #4, because it adds an additional constraint to the function.
EDIT: For the question "Shouldn't every list be equality comparable?":
Lists are comparable iff their elements are comparable. For example, functions, Kleisli arrows, WrappedArrows are not equality comparable, so aren't lists of them.
{-# Language ScopedTypeVariables #-}
myLength :: forall a. Eq a => [a] -> Int
myLength [] = 0
myLength ys = go 1 ys
where
go :: Int -> [a] -> Int
go n xs
| take n xs == take (n+1) xs = n
| otherwise = go (n+1) xs
the function should give me the position of the searched elements.
e. : index 'b' "dfbhjbd" -> [3,6]
I've got so far:
index b (x:xs) = length ( takeWhile ( /= b) xs )
but takeWhile will immediately stop after finding the matching elements. so following elements will be left out.
i tried something like this:
index b (x:xs) = length ( tak b xs )
where
tak b [] = []
tak b xs
| b /= x == x:tak b xs
| otherwise = [], tak b xs
Beside being unable to run the code because of parse error, it would not show the right results.
any suggestions?
you've already seen the problem with takeWhile - I can understand why you tried this (after all you want to use length) but maybe you should try to find a solution where you don't have to use length in the first place.
A good approach might be to keep track of the indizes while you traverse the input list and then look out for the elements equal to `b
if you want to use recursion then you can go all the way:
index :: (Eq a, Num t) => a -> [a] -> [t]
index b xs = index' 1 xs
where
index' _ [] = []
index' i (x:xs)
| b == x = i : index' (i+1) xs
| otherwise = index' (i+1) xs
example
λ> index 'b' "dfbhjbd"
[3,6]
as you can see I'm using a inner function here that takes care of the indizes and the recursion
another approach would be to use zip to get pairs of indizes and elements and then use filter and map to get the results out:
this corresponds to what you tried earlier
index :: (Eq a, Num t, Enum t) => a -> [a] -> [t]
index b xs =
map fst . filter ((== b) . snd) $ zip [1..] xs
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]