I'm trying to write a function that takes a String and an Int and returns that string "int" times. That is:
duplicate :: String -> Int -> String
If I were to write duplicate "Hello" 3 the output should be "HelloHelloHello".
Easily:
duplicate :: String -> Int -> String
duplicate string n = concat $ replicate n string
The $ is a function of type (a -> b) -> a -> b. The language allows the functions with non-alpha-numeric names to be used in infix form (as operators). I.e., the body of the function above is absolutely identical to the following expression:
($) concat (replicate n string)
What $ does is just allows you to get rid of braces. Meaning that the above expressions are just an alternative to the following expression:
concat (replicate n string)
A String is just a synonym for a list of Char, and the list type is a Monad. Therefore
duplicate :: Int -> String -> String
duplicate n str = [1..n] >>= const str
Or, if you wanted to get all point-free
duplicate = (. const) . (>>=) . enumFromTo 1
Edit
As suggested in the comments
duplicate n str = [1..n] >> str
or
duplicate = (>>) . enumFromTo 1
You can use replicate and concat as follows:
duplicate :: [a] -> Int -> [a]
duplicate = flip $ (concat .) . replicate
-- or as larsmans suggested:
duplicate :: [a] -> Int -> [a]
duplicate = (concat .) . flip replicate
Then use it as duplicate "Hello" 3.
You can use pattern matching.
duplicate _ 0 = []
duplicate xs n = xs ++ duplicate xs (n-1)
or
duplicate xs n | n==0 = []
| otherwise = xs ++ duplicate xs (n-1)
Again a beginners attempt, using recursion
duplicate s n = if n <= 1 then s else duplicate (n-1) s ++ s
though it is a little unclear what the function should do if n is negative or zero. So I chose to return the string itself.
Related
I'm trying to write a Haskell function that uses folds and will take a string and return its "word value" as an int. This is the function:
import Data.Char
wordValue :: String -> Int
wordValue (x:xs) = foldr (\(ord(toLower x) - (ord 'a') + 1)) 0 xs
Basically, i'm trying to convert each character into a int value and use the 'foldr' function to accumulate the value. But, I'm getting the following error, which I don't understand:
Parse error in pattern: ord (toLower x) - (ord 'a') + 1
The foldr function also take two parameters: the item of the list, and the result of the foldr of the tail. You thus should implement this as:
wordValue :: String -> Int
wordValue xs = foldr (\x ys -> ord (toLower x) - ord 'a' + ys + 1) 0 xs
where x is the character of the list, and ys is the result of folding the rest of the list (so the wordValue of the remaining elements).
But here it is simpler to just work with a mapping and summing these up, so:
wordValue :: String -> Int
wordValue = sum . map (\x -> ord (toLower x) - ord 'a' + 1)
So I'm pretty new to Haskell, and are trying to solve an assignment, I've solved it, but I'm wondering if there is an easier or prettier way to make a function do the same as my wordChange. I'm trying to only use what is already in prelude.
dictionaryChecker _ [] = False
dictionaryChecker word (x:xs) = if elem word (snd x) then True else dictionaryChecker word xs
wordChange :: String -> String
wordChange str = unwords (map (\s -> if length (translate s) > 0 then (translate s)
else if (dictionaryChecker s dictionary) then concat (replicate (length s) "*")
else s) (words str))
translate :: String -> String
translate str = contains str dictionary
contains _ [] = ""
contains str (x:xs) = if elem str (snd x) then fst x else contains str xs
I'd suggest to use the lookup function from Prelude, which takes a key and a list of tuples (a.k.a a dictionary) and returns Maybe value. This simplfies your function a lot. Also, if changeWord uses a dictionary, it should be explicit instead of using a global variable. Below, a partial solution: since it is an assignment I think you should try to complete it ;)
changeWord :: [(String, String)] -> String -> String
changeWord dic s = unwords $ substitute ws
where -- ws is just the list of words s has
ws = words s
-- the function substitute does the word changing recursively. Try to complete it
substitute [] = []
substitute (x:xs) =
case lookup x dic of -- look for x in the dictionary and returns the value if found
Nothing -> undefined --complete
Just y -> undefined --complete
An obfuscated answer: earn a gold star from your professor if you can explain how it works, and be accused of copying from the internet if you can't:
wordChange :: [(String, String)] -> String -> String
wordChange dict = unwords . map (foldr const <*> (`lookup` dict)) . words
Your dictionaryChecker is in essence an any :: Foldable f => (a -> Bool) -> f a -> Bool with elem word . snd as condition:
dictionaryChecker :: (Foldable f, Foldable g, Eq a) => a -> f (b, g a) -> Bool
dictionaryChecker word = any (elem word . snd)
as for a translate, we can work with a section of an infix operator [Haskell-wiki] to make a point-free function:
translate :: String -> String
translate = (`contains` dictionary)
and for contains we can work with a foldr :: Foldable f => (a -> b -> b) -> b -> f a -> b
contains :: (Foldable f, Foldable g, Eq a) => a -> f (String, g a) -> String
contains str = foldr (\x y -> if … then … else …) ""
I leave implementing the … parts as an exercise.
In the following exercise i want to manipulate a random string input by using functions.
Step 1: I want to remove all characters which are not digits, letters or spaces
Step 2: I want to replace all spaces with '_'
Step 3: I want to convert all numbers to spaces
Step 4: I want to replace all 'a' with 'z' and all 'A' with 'Z'
For lists i already used the filter function and i am wondering if this function can also be used for string inputs. I am not quite sure how to approach this exercise.
Update: I found an approach to solve step 1 and step 3 but i am not quite sure how to put the different functions together in a function which includes every step. Is it possible to call the different functions one after another in the right order in some kind of main function?
import Data.Char
toUpperStr xs = map toUpper xs -- function to convert lower to upper
dropInvalids xs = (filter (\x -> isUpper x || isSpace x || isDigit x)) $
toUpperStr xs
replaceBlank [] = [] -- function to replace " " with "_"
replaceBlank (x:xs) =
if x == ' '
then '_' : replaceBlank xs
else x : replaceBlank xs
Yes, absolutely! That's one of the beautiful things about Haskell.
You can treat Strings as [Char]. In fact, that's what they are!
In GHCi, type :i String - you get type String = [Char].
You can easily compose functions. There's an operator for that, (.).
So (f . g) x is f (g x).
I would improve the code in a few key ways.
Firstly, make the replaceBlank function more general, so it takes a condition and a replacement function.
Secondly, compose all the functions in a "main" function, as you call it.
But do not name the main function main! That name is reserved for the IO action of a program.
It's also important not to think of the final function as "calling" the other functions.
That is imperative terminology, here, we are applying the function(s).
Also, why does your dropInvalids contain a toUpperStr? You never specified the string to be all uppercase in the end.
Also also, be sure to declare the type of your functions.
In this case, the following would be the correct code:
import Data.Char
dropInvalids :: [Char] -> [Char]
dropInvalids = filter (\x -> isLetter x || isSpace x || isDigit x)
-- isLetter exists
replace' :: (a -> Bool) -> (a -> a) -> [a] -> [a]
replace' _ _ [] = []
replace' f g (x:xs) =
if f x
then g x : replace' f g xs
else x : replace' f g xs
-- To replace one value with another, use replace (== a) (const b).
replaceWith :: (a -> Bool) -> a -> [a] -> [a]
replaceWith f b = replace' f (const b)
replace :: Eq a => a -> a -> [a] -> [a]
replace a b = replace' (== a) (const b)
-- The Eq makes sure you can check for equality.
manipulateString :: [Char] -> [Char]
manipulateString = replace 'A' 'Z' . replace 'a' 'z' . replaceWith isDigit ' ' . replace ' ' '_' . dropInvalids
I have been learning some Haskell and I came up with a solution to one of my exercise which I was trying to figure out .
Changes a Char to another specified Char in a specified position in a String
changeStr :: Int -> Char -> String -> String
changeStr x char zs = (take (x-1) zs) ++ [(changeChar (head (take x zs)) char)] ++ (drop x zs)
Changes a Char to another Char
changeChar :: Char -> Char -> Char
changeChar x y = y
I just wanted to ask is there any other way in which I could do this in a more simpler way using different methods ?
The thing that screams for generalization is changeChar. It's actually very close to a very common Haskell Prelude function called const. To get changeChar we just need to flip const.
const :: a -> b -> a
const a b = a
changeChar :: Char -> Char -> Char
changeChar = flip const
-- = flip (\a _ -> a)
-- = \_ a -> a
-- _ a = a
Beyond that, your code is fairly reasonable, but can be cleaned up by using a function splitAt
splitAt :: Int -> [a] -> ([a], [a])
splitAt n xs = (take n xs, drop n xs)
changeChar x char xs =
let (before, _it:after) = splitAt (x - 1)
in before ++ (char:after)
which also highlights a slight problem with this definition in that if your index is too large it will throw a pattern matching failure. We could fix that by making the function return an unmodified string if we "fall off the end"
changeChar x char xs =
let (before, after) = splitAt (x - 1)
in case after of
[] -> []
(_:rest) -> char:rest
There's a general pattern here as well of applying a modifying function at a particular place in a list. Here's how we can extract that.
changeAt :: Int -> (a -> a) -> [a] -> [a]
changeAt n f xs =
let (before, after) = splitAt (n-1)
in case after of
[] -> []
(x:rest) -> (f x):rest
We can use this to iterate the notion
-- | Replaces an element in a list of lists treated as a matrix.
changeMatrix :: (Int, Int) -> a -> [[a]] -> [[a]]
changeMatrix (i, j) x = changeAt i (changeAt j (const x))
What you have is pretty much what you need, except the function changeChar is just flip const, and you could rewrite yours as
changeStr x char zs = take (x-1) zs ++ [char] ++ drop x zs
If you wanted to be complicated, you could use splitAt from Data.List and the fact that fmap f (a, b) = (a, f b)
changeStr idx c str = uncurry (++) $ fmap ((c:) . tail) $ splitAt (idx - 1) str
And if you wanted to be really complicated, you could ask the pointfree bot how to write it without explicit function arguments
changeStr = ((uncurry (++) .) .) . flip ((.) . fmap . (. tail) . (:)) . splitAt . subtract 1
So I write a function with the definition
getLastDigits :: String -> String
which finds repeating digits on the end of a String
So, for example.
getLastDigits "1000" should give "000"
getLastDigits "19990299" should give "99"
Coming from a java background I'm not quite sure how to structure this program. I'm thinking of using foldr but I'm fairly sure I can't stop the fold half way when the repeating digits end.
-edit solved. Use the group function.
Okay then, if it is not homework:
lastDigits :: String -> String
lastDigits s = firstDigits . reverse $ s
where firstDigits :: String -> String
firstDigits (x:xs) = x : takeWhile (== x) xs
firstDigits [] = []
import Data.Char (isDigit)
getLastTheSame :: Eq a => (a -> Bool) -> [a] -> [a]
getLastTheSame pred xs = f (reverse xs)
where f (y : ys) | pred y = y : takeWhile (== y) ys
f _ = []
lastDigits :: String -> String
lastDigits = getLastTheSame isDigit
You say you want repeating digits from the end of the string. I presume that if the last character is not a digit then you want the empty string returned.
Recall that type String = [Char].