I'm new to Haskell and I'm trying to shift a character by one to the right and that the last character will always be first, and that it would return a string.
For example: shiftString "abcd" = "dabc" but the compiler doesn't agree with me, can anybody help me fix this?
shiftString :: String -> String
shiftString x = take (length x) $ iterate rot1 x
where rot1 = drop 1 x ++ take 1 x
Also, I want to check after this on two Strings and returns True if one of them is a result of applying shiftString one or more times, how can I use this to do that? as in:
isShifted :: String -> String -> Bool
A String in Haskell is just a list of Chars - so you can do this using simple pattern-matching:
shiftString' :: String -> String
shiftString' (firstChar:restChars) = restChars ++ [firstChar]
shiftString' [] = []
now if you try this it'll do the opposite of what you want - but there is a trick: we reverse the string twice:
shiftString :: String -> String
shiftString = reverse . shiftString' . reverse
that should do the trick
fix yours:
I think you only need the rot1 (it does the same as my shiftString') together with the reverse trick from above
Or - to fix yours more:
I guess you tried with the iterate to rot1 more times and then drop the rest - that works too:
shiftS cs = head $ drop (length cs - 1) $ iterate rot1 cs
rot1 cs = drop 1 cs ++ take 1 cs
note that iterate gives you a list of strings (with more and more rotations) - I drop the first n-1 (where n = length of the input) which gives me a list again (one type-error on your version) and take the head of that because I only want the first String in this list.
for your isShifted you can reuse the iterate with rot1 (no need to care about order) - this time take length cs from this and then check if your other input is an element of this list:
isShifted cs cs' = cs `elem` take (length cs) (iterate rot1 cs')
Example:
Prelude> isShifted "abcd" "cdab"
True
Prelude> isShifted "abdc" "cdab"
False
note that you cannot just use iterate rot1 cs' without the take - think about it and then try what happens ;) (hint: it'll work when your inputs are shifted - but you'll get into trouble if they are not - why?)
-- shiftString "abcd" == "dabc"
-- shiftString "hello" == "ohell"
-- shiftString "orange" == "eorang"
shiftString :: [a] -> [a]
shiftString lst = [ head (reverse lst)] ++ (init lst)
-- Test Cases
-- isShifted "abcdefg" "gabcdef" == True
-- isShifted "hello" "ohell" == True
-- isShifted "orange" "eorange" == False
isShifted :: String -> String -> Bool
isShifted str1 str2
| shiftString str1 == str2 = True
| otherwise = False
Related
I'm new to the Haskell. I am finding following task difficult:
Enter a string of characters. Output all palindromes to the file (use the IO monad to work with the file system and input / output, use the list monad to work with the strings).`
Any code is may be helpful. Thank you in advance!
This is what I have tried so far:
palindrome :: Char -> [String]
palindrome n
| n < 0 = []
| even n = map (\front -> front ++ reverse front) fronts
| odd n = map (\front -> front ++ tail (reverse front)) fronts
where ispalindrome :: (Integral a, Show a) => a -> Bool
ispalindrome x = show x = reverse (show x)
main = do
input <- getline
putStrLn print :: IO ()
So this is basically consists of 4 things.
Read Input from the stdin
Convert input string into list of strings
From the above list find out the strings which are palindromes
print these palindromes into file.
If you convert above into functions the signatures of these will be.
String -> [String]
[String] -> [String]
Don't bother about the signature of 1st and 4th for now. These are anyways one line code readily available on internet.
2 is a single function available in Data.List called words.
3 can be again in two parts. A function which find out if a given string is palindrome. Signature will be
String -> Bool
This is also one line code.
Once you have above function the only part remaining is filtering out the strings which are palindromes in given list of strings.
isPalindrome
My haskell is a bit rusty so I don't promise the code below will work %100 yet I tried to stick to the main idea.I hope this answer helps. If you think anything is wrong both logically and syntactically, just write a comment and I will fix it asap.
isPalindrome :: [Char] -> Boolean
isPalindrome w = isPalindrome' w reverse w
where
isPalindrome' :: [Char] -> [Char] -> Boolean
isPalindrome' [] [] = true
isPalindrome' (x:xs) (y:ys) = if x == y then isPalindrome' xs ys else false
isPalindrome' _ _ = false
function above should be fine for checking for palindromes.
for writing to file part, you can create a list of palindromes first, then write all palindromes to a file in another function. so basically, first you split your string into words, then for words in given string you find palindromes, then you write the palindromes into a file.
how to read string from user?
main = do
userInput <- getLine
how to split word with delimiter?
split :: Char -> [Char] -> [[Char]]
split delimiter string = split' delimiter string [] []
where
split' :: Char -> [Char] -> [Char] -> [[Char]] -> [[Char]]
split' delim [] substr splittedStr = splittedStr if substr == [] else reverse substr ++ splittedStr
split' delim (x:xs) substr splittedStr = if x == delim then split' delim xs [] (reverse substr) ++ splittedSubstr else split' delim xs (x ++ substr) splittedSubstr
main idea is you stack characters until you see your delimeter and store them in a list when you see a delimiter.
how to filter palindromes in list?
to filter palindromes in list you use haskell's filter function as
filter isPalindrome (split ' ' userInput)
In the end, you can write a main block to run all of this in right order
main = do
userInput <- getLine
let splittedInput = split ' ' userInput
let palindromes = filter isPalindrome splittedInput
let output = concat (intersperse "\n" palindromes)
writeFile "file.txt" output
I want to rotate a string in haskell, so if I give "Now I want to scream" to rotate [[want to scream now I],[scream now I want to]] , if the string start with "I" or "to" then must eliminate it. Till now I still have problems with the rotation.
reverseWords :: String -> String
reverseWords = unwords . reverse . words
shiftt :: [a] -> Int -> [a]
shiftt l n = drop n l ++ take n l
rot::String->[String]
rot l = [ reverseWords l i | i <- [0 .. (length l) -1]]
create a list of all rotations, then filter out based on your predicate. For example,
rotations x = take (length x) $ iterate rot1 x
where rot1 = drop 1 x ++ take 1 x
filteredRots = map unwords . filter (\x -> length (head x) > 2) . rotations . words
and use as
> filteredRots "Now I want to scream"
["Now I want to scream","want to scream Now I","scream Now I want to"]
Prelude>
(1.) The function "sameString" returns a Boolean value for whether two strings are the same regardless of capitalisation.
-- *Main> sameString "HeLLo" "HElLo"
-- True
-- *Main> sameString "Hello" "Hi there"
-- False
sameString :: String -> String -> Bool
sameString str1 str2
| length str1 == length str2 = and [ a == b | (a,b) <- zip (capitalise str1) (capitalise str2) ]
| otherwise = False
(1) Helper function "capitalise" does the capitalising.
capitalise :: String -> String
capitalise str = [ toUpper x | x <- str ]
(2) Function "prefix" returns a Boolean value which states whether the first string is a prefix of the second, regardless of capitalisation.
-- *Main> prefix "bc" "abCDE"
-- False
-- *Main> prefix "Bc" "bCDE"
-- True
prefix :: String -> String -> Bool
prefix [] [] = True
prefix substr str
| sameString string' substr == True = True
| otherwise = False
where chop_str :: String -> String -> String
chop_str str substr = (take (length substr) str)
string' = chop_str str substr
(3.) Function "dropUntil" returns the contents of the second string after the first occurrence of the first string. If the second string does not contain the first as a substring, it should return the empty string.
*Main> dropUntil "cd" "abcdef"
"ef"
dropUntil :: String -> String -> String
dropUntil substr [] = ""
dropUntil substr (s:tr)
| prefix substr (s:tr) == False = drop 1 s : dropUntil substr tr
| prefix substr (s:tr) == True =
So now the question. I was thinking of doing dropUntil with recursion.
What I think the function above should do is:
1) Given a string and a substring (for which the substring is not the prefix of the string) ...
it should drop the head of the string ...
and cons the empty list "" to
... a recursive call on the remaining tail and the same substring.
The idea behind it is to keep dropping the head of the list until the substring becomes the prefix of the list, where the function should then produce the remainder of the string as a result.
However, I have no idea how to do this. What I essentially want to do is make
| prefix substr (s:tr) == True = "leftover_string"
Where "leftover_string" is what remains after the recursive call drops the elements until the condition is met that the substring is the prefix of the remainder.
Is this possible to do the way I started?
We've had a lot of questions in the past couple of days which involve running down an equatable [x] with some other [x] looking for isPrefixOf. One primitive which has emerged in my thought process since then is really valuable here:
import Data.List
splitAtSublist :: ([x] -> Bool) -> [x] -> Maybe ([x], [x])
splitAtSublist pred list = find (pred . snd) $ zip (inits list) (tails list)
The splittings zip (inits list) (tails list) for a string "abcd" look like [("", "abcd"), ("a", "bcd"), ("ab", "cd"), ("abc", "d"), ("abcd", ""))]. This finds the first element where the "tail end" of the splitting satisfies the predicate pred.
To get dropUntil s from this basis we can just do:
dropUntil p ls =
maybe "" (drop (length p) . snd) $
splitAtSublist (p `isPrefixOf`) ls
where isPrefixOf is from Data.List too. Substituting in, we find out that we don't use the inits list at all and it just becomes:
dropUntil p = maybe "" (drop $ length p) . find (p `isPrefixOf`) . tails
which is as simple as I can get it.
Is this what you want?
| prefix substr (s:tr) == True = drop (length substr) (s:tr)
Some notes:
You have a type error here:
| prefix substr (s:tr) == False = drop 1 s : dropUntil substr tr
^^^^^^^^
I think you just want:
| prefix substr (s:tr) == False = dropUntil substr tr
I have a string "AB0123456789" and the output I would like to have is: "AB01 2345 6789" ... I want to add a space after every fourth character. How can I do this?
Main> addSpace "AB0123456789"
"AB01 2345 6789"
With Data.List.intercalate and Data.List.Split.chunksOf this is easy:
import Data.List.Split
addSpace :: String -> String
addSpace = intercalate " " . chunksOf 4
This may not be the most efficient:
addSpace xs = if length xs <= 4
then xs
else take 4 xs ++ " " ++ addSpace (drop 4 xs)
Demo in ghci:
ghci > addSpace "AB0123456789"
"AB01 2345 6789"
I would think pattern matching would make this easiest:
addSpaces :: String -> String
addSpaces xs#(_:_:_:_:[]) = xs
addSpaces (a:b:c:d:xs) = a:b:c:d:' ':addSpaces xs
addSpaces xs = xs
You have to include the first case so you don't potentially get a space at the end, but it's pretty straightforward. This isn't extensible, though, you wouldn't be able to use a function like this to dynamically choose how many characters you want to skip before inserting a space (such as in #cdk's answer)
You can use splitAt. Heres a function that adds space after every nth character.
spaceN :: Int -> String -> String
spaceN n = init . go
where go [] = []
go xs = let (as, bs) = splitAt n xs in as ++ (' ' : go bs)
for your specific case:
λ. spaceN 4 "AB0123456789"
"AB01 2345 6789"
window :: Int -> [a] -> [[a]]
window i = unfoldr (\l -> if null l then Nothing else Just (splitAt i l))
addSpace :: String -> String
addSpace = intercalate " " . window 4
Supposing I had the string "HELLO WORLD" is there a way I can call a function that replaces the character 'O' in the string with the character 'X' so that the new string would look like "HELLX WXRLD"?
How about:
let
repl 'o' = 'x'
repl c = c
in map repl "Hello World"
If you need to replace additional characters later, just add clauses to the repl function.
Sorry for picking up this old thread but why not use lambda expressions?
λ> let replaceO = map (\c -> if c=='O' then 'X'; else c)
λ> replaceO "HELLO WORLD"
"HELLX WXRLD"`
Alternative 1 - Using MissingH
First:
import Data.List.Utils (replace)
Then use:
replace "O" "X" "HELLO WORLD"
Alternative 2 - Using Control.Monad
One funny bastard:
import Control.Monad (mfilter)
replace a b = map $ maybe b id . mfilter (/= a) . Just
Example:
λ> replace 'O' 'X' "HELLO WORLD"
"HELLX WXRLD"
Alternative 3 - Using if
Amon's suggestions was probably the finest I believe! No imports and easy to read and understand!
But to be picky - there's no need for semicolon:
replace :: Eq a => a -> a -> [a] -> [a]
replace a b = map $ \c -> if c == a then b else c
If you depend on the text package (like 99.99% of Haskell applications), you can use T.replace:
>>> replace "ofo" "bar" "ofofo"
"barfo"
Here's another possible solution using divide and conquer:
replaceO [] = []
replaceO (x:xs) =
if x == 'O'
then 'X' : replaceO xs
else x : replaceO xs
First, you set the edge condition "replaceO [] = []".
If the list is empty, there is nothing to replace, returning an empty list.
Next, we take the string and divide it into head and tail. in this case 'H':"ELLOWORLD"
If the head is equal to 'O', it will replace it with 'X'. and apply the replaceO function to the rest of the string.
If the head is not equal to 'O', then it will put the head back where it is and apply the replaceO function to the rest of the string.
replace :: Char -> Char -> String -> String
replace _ _ [] = []
replace a b (x : xs)
| x == a = [b] ++ replace a b xs
| otherwise = [x] ++ replace a b xs
I'm new to Haskell and I've tried to make it simpler for others like me.
I guess this could be useful.
main = print $ charRemap "Hello WOrld" ['O','o'] ['X','x']
charRemap :: [Char] -> [Char] -> [Char] -> [Char]
charRemap [] _ _ = []
charRemap (w:word) mapFrom mapTo =
if snd state
then mapTo !! fst state : charRemap word mapFrom mapTo
else w : charRemap word mapFrom mapTo
where
state = hasChar w mapFrom 0
hasChar :: Char -> [Char] -> Int -> (Int,Bool)
hasChar _ [] _ = (0,False)
hasChar c (x:xs) i | c == x = (i,True)
| otherwise = hasChar c xs (i+1)