While loop in Haskell - haskell

I want to create a while loop to concatenate strings in the xs list
until I find an empty string, but it seems neither we have a chance to
increment an Int nor create a while loop.
So this looks like a pseudo code for Haskell, but how can I actually implement my solution?
prt :: String -> [String] -> Int -> String
prt str xs x = do
while((xs !! (x)) /= "")
str = str ++ (xs !! (x++))

Forget array indexes: they are often not needed. All you have to do for your task is getting the longest prefix of your list containing only non-empty strings.
takeWhile (not . null) xs
-- or
takeWhile (/= "") xs
Then you want to concatenate these strings.
concat $ takeWhile (/= "") xs
If you want to start after n strings for some reason, just drop the first n before beginning:
concat $ takeWhile (/= "") $ drop n xs
If you really want to do a custom "loop", use recursion:
g xs n = f $ drop n xs
f [] = ""
f ("":xs) = ""
f (x:xs) = x ++ f xs

Related

How do i syntax in haskell

Im trying to write a function that takes in a string and then returns the string as a list of string-words (like the words built-in function) and so far i've written
ord :: String -> [String]
ord [] = []
ord xs = let
ys = groupBy (\x y -> y /= ' ') xs
in filter (not . null) ys
I thougth this would get rid of the empty strings from the list but i only get this output
input:
ord “aa b c - dd”
output:
["aa"," b"," "," "," "," "," "," "," c"," "," "," -"," "," "," "," dd"]
when this is the output i want:
[“aa”, ”b”, ”c”, ”-“, ”dd”]
I get the same result if i try and write
ord :: String -> [String]
ord [] = []
ord xs = filter (not . null) ys
where
ys = groupBy (\x y -> y /= ' ') xs
How do i re-write this code so that i rid the list of its empty strings?
Or use the proper syntax? Im just learning Haskell and im still having trouble with the syntax...
groupBy means that you put x and y in the same group, given the condition is satisfied. But here you group the two together, given y is not equal to a space.
You thus can alter your grouping predicate, and put x and y in the same group, given both are spaces, or non-spaces:
import Data.Char(isSpace)
ord :: String -> [String]
ord [] = []
ord xs = let
ys = groupBy (\x y -> isSpace x == isSpace y) xs
in filter (not . null) ys
or shorter:
import Data.Char(isSpace)
import Data.Function(on)
ord :: String -> [String]
ord [] = []
ord xs = let
ys = groupBy (on (==) isSpace) xs
in filter (not . null) ys
Now we retrieve:
Prelude Data.List> ord "aa b c - dd"
["aa"," ","b"," ","c"," ","-"," ","dd"]
We of course still not obtain the expected result. In stead of filtering out empty strings, we can filter out strings that only contain spacing characters:
import Data.Char(isSpace)
import Data.Function(on)
ord :: String -> [String]
ord [] = []
ord xs = let
ys = groupBy (on (==) isSpace) xs
in filter (not . all isSpace) ys
We do not need to covert the empty case manually, since groupBy on an empty list produces an empty list, we can thus construct a one liner to do the processing:
import Data.Char(isSpace)
import Data.Function(on)
ord :: String -> [String]
ord = filter (not . all isSpace) . groupBy (on (==) isSpace)
Then we obtain the expected result:
Prelude Data.List Data.Char> ord "aa b c - dd"
["aa","b","c","-","dd"]
I wouldn't bother with groupBy at all here. In particular, there's no need to build lists of spaces just to throw them away. Let's start with a function that drops initial spaces and then grabs everything to the first space:
grab :: String -> (String, String)
grab = break isSpace . dropWhile isSpace
Note that the first component of grab xs will be empty if and only if all the elements of xs are spaces.
Now we can write
myWords :: String -> [String]
myWords xs = case grab xs of
([], _) -> []
(beginning, end) -> beginning : myWords end

How to convert a String to lowercase using lambda expressions

I want to know how to convert a string to lowercase using the ToLower function (Char -> Char).
This is the code I have so far:
let newlist = (\(h:t) -> c (h) ++ newlist (\c -> toLower c)
I can't see how to do it without using recursion, which I don't know how to use in a lambda expression
It would be easier to not use a lambda expression considering you can eta-reduce to not explicitly name the variable your function accepts. For example you could use a list comprehension:
import Data.Char
lowerString str = [ toLower loweredString | loweredString <- str]
Which you would call as:
ghci> lowerString "Hello"
hello
Alternatively, you could use map:
lowerString = map toLower
If you insist on using a lambda expression, it would look something like this:
import Data.Char
lowerString = \x -> map toLower x
Which again, is not as nice.
With a lambda expression you'd still need to recursively check each character of the string, or you could use map which is still a recursive function that applies the function (a -> b) to every element in the list, for example:
newList [] = []
newList xs = (\(y:ys) -> if x `elem` ['A'..'Z'] then toLower y : newList ys else y : newList ys) xs
With map is actually much simpler due to reasons explained in the first paragraph, check mnoronha's answer as he already gave you the answer, but that's if you're thinking of using map in conjunction with toLower.
This is an example without a lambda expression, which requires you to import 2 functions from Data.Char, recursively check the rest of the string and replace each character with its lower case version.
newList :: String -> String
newList [] = []
newList (x:xs) = if x `elem` ['A'..'Z']
then chr (ord x + 32) : newList xs
else x : newList xs
or with guards
newList :: String -> String
newList [] = []
newList (x:xs)
| x `elem` ['A'..'Z'] = chr (ord x + 32) : newList xs
| otherwise = x : newList xs
This may be more trouble than it's worth but you can use the fix function to recursively call a lambda function.
fix :: (a -> a) -> a
fix f = let x = f x in x
The following code uses the same method used on this page : https://www.vex.net/~trebla/haskell/fix.xhtml to transition from a non-lambda version to a lambda version to (eventually) using fix to recursively call a lambda function without introducing a new variable
import Data.Char (toLower)
import Control.Monad.Fix (fix)
main :: IO ()
main = do
-- calling non lambda version
let newlist1 s = if null s then [] else toLower (head s) : newlist1 (tail s)
print $ newlist1 "Hello"
-- calling lambda version
let newlist2 = \s -> if null s then [] else toLower (head s) : newlist2 (tail s)
print $ newlist2 "Hello"
-- defining lambda version locally
-- ( at this point the scope of newlist3 is local to the let statement )
print $ (let newlist3 = \s -> if null s then [] else toLower (head s) : newlist3 (tail s) in newlist3 ) "Hello"
-- making function an argument to be called recursively
print $ (let newlist3 = (\v -> \s -> if null s then [] else toLower (head s) : v (tail s)) newlist3 in newlist3 ) "Hello"
-- isolating function to be "fixed".
let f = (\v -> \s -> if null s then [] else toLower (head s) : v (tail s))
print $ (let newlist3 = f newlist3 in newlist3 ) "Hello"
-- using fix = let x = f x in x
print $ (fix f) "Hello"
-- f2 is slightly simpler version of f
let f2 = (\v s -> if null s then [] else toLower (head s) : v (tail s))
print $ (fix f2) "Hello"
-- inlining f2 to get recursive call to lambda
print $ (fix (\v s -> if null s then [] else toLower (head s) : v (tail s))) "Hello"

Remove characters from String in Haskell

I am creating a program that reads a text file and splits up words and stores them in a list. I have been trying to create a function that takes in a String which is the whole text String from the file and remove punctuation e.g. ";", ",", "." but unfortunately haven't had any luck yet. The program works without the punctuation function, but not when I include it to (toWords fileContents) Please can someone look at what I have done and see what I am doing wrong.
Here is the code that I have so far:
main = do
contents <- readFile "LargeTextFile.txt"
let lowContents = map toLower contents
let outStr = countWords (lowContents)
let finalStr = sortOccurrences (outStr)
let reversedStr = reverse finalStr
putStrLn "Word | Occurrence "
mapM_ (printList) reversedStr
-- Counts all the words.
countWords :: String -> [(String, Int)]
countWords fileContents = countOccurrences (toWords (removePunc fileContents))
-- Splits words and removes linking words.
toWords :: String -> [String]
toWords s = filter (\w -> w `notElem` ["an","the","for"]) (words s)
-- Remove punctuation from text String.
removePunc :: String -> String
removePunc xs = x | x <- xs, not (x `elem` ",.?!-:;\"\'")
-- Counts, how often each string in the given list appears.
countOccurrences :: [String] -> [(String, Int)]
countOccurrences xs = map (\xs -> (head xs, length xs)) . group . sort $ xs
-- Sort list in order of occurrences.
sortOccurrences :: [(String, Int)] -> [(String, Int)]
sortOccurrences sort = sortBy (comparing snd) sort
-- Prints the list in a format.
printList a = putStrLn((fst a) ++ " | " ++ (show $ snd a))
You probably want:
removePunc xs = [ x | x <- xs, not (x `elem` ",.?!-:;\"\'") ]
with the brackets.

Haskell - format issue

i am a beginner in haskell programming and very often i get the error
xxx.hs:30:1: parse error on input `xxx'
And often there is a little bit playing with the format the solution. Its the same code and it looks the same, but after playing around, the error is gone.
At the moment I've got the error
LookupAll.hs:30:1: parse error on input `lookupAll'
After that code:
lookupOne :: Int -> [(Int,a)] -> [a]
lookupOne _ [] = []
lookupOne x list =
if fst(head list) == x then snd(head list) : []
lookupOne x (tail list)
-- | Given a list of keys and a list of pairs of key and value
-- 'lookupAll' looks up the list of associated values for each key
-- and concatenates the results.
lookupAll :: [Int] -> [(Int,a)] -> [a]
lookupAll [] _ = []
lookupAll _ [] = []
lookupAll xs list = lookupOne h list ++ lookupAll t list
where
h = head xs
t = tail xs
But I have done everything right in my opinion. There are no tabs or something like that. Always 4 spaces. Is there a general solutoin for this problems? I am using notepad++ at the moment.
Thanks!
The problem is not with lookupAll, it's actually with the previous two lines of code
if fst (head list) == x then snd (head list) : []
lookupOne x (tail list)
You haven't included an else on this if statement. My guess is that you meant
if fst (head list) == x then snd (head list) : []
else lookupOne x (tail list)
Which I personally would prefer to format as
if fst (head list) == x
then snd (head list) : []
else lookupOne x (tail list)
but that's a matter of taste.
If you are wanting to accumulate a list of values that match a condition, there are a few ways. By far the easiest is to use filter, but you can also use explicit recursion. To use filter, you could write your function as
lookupOne x list
= map snd -- Return only the values from the assoc list
$ filter (\y -> fst y == x) list -- Find each pair whose first element equals x
If you wanted to use recursion, you could instead write it as
lookupOne _ [] = [] -- The base case pattern
lookupOne x (y:ys) = -- Pattern match with (:), don't have to use head and tail
if fst y == x -- Check if the key and lookup value match
then snd y : lookupOne x ys -- If so, prepend it onto the result of looking up the rest of the list
else lookupOne x ys -- Otherwise, just return the result of looking up the rest of the list
Both of these are equivalent. In fact, you can implement filter as
filter cond [] = []
filter cond (x:xs) =
if cond x
then x : filter cond xs
else filter cond xs
And map as
map f [] = []
map f (x:xs) = f x : map f xs
Hopefully you can spot the similarities between filter and lookupOne, and with map consider f == snd, so you have a merger of the two patterns of map and filter in the explicit recursive version of lookupOne. You could generalize this combined pattern into a higher order function
mapFilter :: (a -> b) -> (a -> Bool) -> [a] -> [b]
mapFilter f cond [] = []
mapFilter f cond (x:xs) =
if cond x
then f x : mapFilter f cond xs
else : mapFilter f cond xs
Which you can use to implement lookupOne as
lookupOne x list = mapFilter snd (\y -> fst y == x) list
Or more simply
lookupOne x = mapFilter snd ((== x) . fst)
I think #bheklilr is right - you're missing an else.
You could fix this particular formatting problem, however, by forming lookupOne as a function composition, rather than writing your own new recursive function.
For example, you can get the right kind of behaviour by defining lookupOne like this:
lookupOne a = map snd . filter ((==) a . fst)
This way it's clearer that you're first filtering out the elements of the input list for which the first element of the tuple matches the key, and then extracting just the second element of each tuple.

Haskell filter string with only the first occuring Char

I want to filter a string with a string.
What I want is to use delete every first occurring char.
myFunc :: String -> String -> String
Like:
myFunc "dddog" "bigdddddog" = "biddg"
In "dddog": 3x d, 1x o, 1x g
In the second string it removed 3x d, 1x o and 1x g
So the output: biddg
I can't use filter for it, because it will delete all occurring chars.
And I struggled a long time with it.
Thanks in advance:)
How about
Prelude> :m +Data.List
Prelude Data.List> "bigdddddog" \\ "dddog"
"biddg"
Not the nicest solution, but you can understand easier what's going on:
myfunc :: String -> String -> String
myfunc [] xs = xs
myfunc (x:xs) ys = myfunc xs $ remove x ys
where
remove _ [] = []
remove x (y:ys) = if x == y then ys else y : remove x ys
As you commented, you want to use guards. Do you mean this?
myfunc :: String -> String -> String
myfunc [] xs = xs
myfunc (x:xs) ys = myfunc xs $ remove x ys
remove :: Char -> String -> String
remove _ [] = []
remove x (y:ys)
| x == y = ys
| otherwise = y : remove x ys
some of the other solutions don't seem to produce the same result you posted. I think I have a simple solution that does what you asked for but I may be misunderstanding what you want. All I do in the following code is go though the list and apply 'delete' to every element in the list. It's not exactly efficient but it gets the job done.
import Data.List
myFunc (x:xs) ys = myFunc xs (delete x ys)
myFunc [] ys = ys
There are perhaps more efficient solutions like storing the "to remove" list in a tree with the number of occurences stored as the value then traversing the main list testing to see if the count at that key was still greater than zero. I think that would give you O(n*lg(m)) (where n is the size of the list to be removed from and m is the size of the "to remove" list) rather than O(n*m) as is the case above. This version could also be maid to be lazy I think.
edit:
Here is the tree version I was talking abut using Data.Map. It's a bit complex but should be more efficient for large lists and it is somewhat lazy
myFunc l ys = myFunc' (makeCount l) ys
where makeCount xs = foldr increment (Map.fromList []) xs
increment x a = Map.insertWith (+) x 1 a
decrement x a = Map.insertWith (flip (-)) x 1 a
getCount x a = case Map.lookup x a of
Just c -> c
Nothing -> 0
myFunc' counts (x:xs) = if (getCount x counts) > 0
then myFunc' (decrement x counts) xs
else x : myFunc' counts xs
myFunc' _ [] = []
I am not quite sure about how you want your function to behave, how about this?
import Data.List (isPrefixOf)
myFunc :: String -> String -> String
myFunc _ [] = []
myFunc y x'#(x:xs) | y `isPrefixOf` x' = drop (length y) x'
| otherwise = x : myFilter xs y
This gives the following output in GHCi:
> myFunc "dddog" "bigdddddog"
> "bigdd"
If this is not what you had in mind, please give another input/output example.
I like kaan's elegant solution. In case you meant this...here's one where the "ddd" would only be removed if matched as a whole:
import Data.List (group,isPrefixOf,delete)
f needles str = g (group needles) str where
g needles [] = []
g needles xxs#(x:xs)
| null needle' = [x] ++ g needles xs
| otherwise = let needle = head needle'
in g (delete needle needles) (drop (length needle) xxs)
where needle' = dropWhile (not . flip isPrefixOf xxs) needles
Output:
*Main> f "dddog" "bigdddddog"
"biddg"
*Main> f "dddog" "bdigdogd"
"bdidgd"
No monadic solution yet, there you go:
import Control.Monad.State
myFunc :: String -> State String String
myFunc [] = return ""
myFunc (x:xs) = get >>= f where
f [] = return (x:xs)
f (y:ys) = if y == x then put ys >> myFunc xs
else myFunc xs >>= return . (x:)
main = do
let (a,b) = runState (myFunc "bigdddddog") "dddog" in
putStr a
Using predefined functions from Data.List,
-- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
-- lookup :: (Eq a) => a -> [(a, b)] -> Maybe b
{-# LANGUAGE PatternGuards #-}
import Data.List
picks [] = [] -- http://stackoverflow.com/a/9889702/849891
picks (x:xs) = (x,xs) : [ (y,x:ys) | (y,ys) <- picks xs]
myFunc a b = concat . snd $ mapAccumL f (picks a) b
where
f acc x | Just r <- lookup x acc = (picks r,[])
f acc x = (acc,[x])
Testing:
Prelude Data.List> myFunc "dddog" "bigdddddog"
"biddg"
edit: this is of course a bit more complex than (\\). I'll let it stand as an illustration. There could be some merit to it still, as it doesn't copy the 2nd (longer?) string over and over, for each non-matching character from the 1st (shorter) string, as delete apparently does, used in (\\) = foldl (flip delete).

Resources