counting lower and uppercase characters in haskell - haskell

Im a beginner to haskell and I've tried to create a function which counts the numbers of a character in a string. The problem I have is that I am only able to count either the number of occurences of a uppercase or a lowercase character. I want to count both of them. E.g. For the string Mum the result for counting m should be 2.
My function right now looks like this:
import Data.Char
countList :: [Char] -> Char -> Int
countList str c = length $ filter (== c) str
What would your suggestions on solving this be?

import Data.Char (toUpper)
countChar :: Char -> [Char] -> Int
countChar char = length . filter (\c -> toUpper c == toUpper char)
countChar 's' "Stdudents" => 2
countChar 'S' "Sstudents" => 3
countChar 'S' "$tudent$$" => 0
Given a character 'char', filter the entire string for any character whose uppercase matches the uppercase of 'char'. Feed the new filtered string to the 'length' function to get the total count.

A neat way to obtain the toUpper c == toUpper char comparison is to use the on combinator:
import Data.Function
countChar char = length . filter (on (==) toUpper char)

Just transform all to lowercase:
import Data.Char
countList :: [Char] -> Char -> Int
countList str c = length $ filter (== toLower c) $ map toLower str
You can also use just use fold, here a ghci example:
Prelude Data.Char> let countList = \str c -> foldl (\x y -> x + if ((toLower y) == (toLower c)) then 1 else 0) 0 str
Prelude Data.Char> countList "AAaabCC" 'a'
4

Related

how to check if a number is in octal in Haskell

I need a program that receives a String containing an octal number and converts it to decimal. If the String contains anything that's not a number from 0 to 8, the function should return a 0.
This is what I got:
octoDec :: [Char] -> Int
octoDec [] = 0
octoDec (x:xs) = ((digitToInt(x)) * 8 ^(length xs)) + octoDec xs
If I enter octoDec ['1','2','3'] I get 83 , which is expected. However, how can I validate the user's without needing another function?
Edit: I've manage to build a function that checks if a number contains only digits between 0 and 7:
isOcto :: [Char] -> Bool
isOcto [] = True
isOcto (x:xs) | (digitToInt(x) > 0) && digitToInt(x) < 7 = isOcto (xs)
|otherwise = False
what i wanted is to merge these two functions into one and return zero to invalid.
If you want octoDec to not only return the result, but also determine whether a result is even possible, return a Maybe Int instead of Int:
octoDec :: [Char] -> Maybe Int
octoDec [] = Just 0
octoDec (x:xs) = do
rest <- octoDec xs
let d = digitToInt x
guard $ d >= 0 && d <= 7
pure $ rest + d * 8^length xs
The guard function from Control.Monad will make the whole do block return Nothing if the condition doesn't hold.
First, you'll want to use Horner's Method to efficiently convert a sequence of digits to a single value.
> foldl (\acc n -> 8*acc + n) 0 (map digitToInt "123")
83
map digitToInt parses the string, and
foldl (\acc n -> 8*acc + n) 0 is a function that evaluates the result of the parse.
horner :: [Int] -> Int
horner = foldl (\acc n -> 8*acc + n) 0
parseString :: [Char] -> [Int]
parseString = fmap digitToInt
octoDec :: [Char] -> Int
octoDec = horner . parseString
However, digitToInt isn't quite right: it can accept digits greater than 7,
> parseString "193"
[1,9,3]
and raises an exception for a value that isn't a digit at all.
> parseString "foo"
[15,*** Exception: Char.digitToInt: not a digit 'o'
We can write a better a function:
octalDigitToInt :: Char -> Maybe Int
octalDigitToInt c | c `elem` "01234567" = Just (digitToInt c)
| otherwise = Nothing
We can use that to convert an octal number into a sequence of digits, using traverse instead of fmap:
parseString' :: [Char] -> Maybe [Int]
parseString' = traverse octalDigitToInt
Valid octal string produce a Just value:
> parseString' "123"
Just [1,2,3]
while invalid strings produce a Nothing value:
> parseString' "193"
Nothing
> parseString' "foo"
Nothing
(Think of traverse as being a function that not only applies a function to a list of values, but only produces a list of results if each application succeeds. More precisely, it's a combination of sequence and fmap:
traverse f = sequence . fmap f
where sequence is the function that "inverts" a value of type [Maybe Int] to a value of type Maybe [Int].)
With a more robust version of parseString, we need to adapt octoDec to handle the possibility that parsing will fail. We do that by using fmap to "lift" horner into the Maybe functor.
octoDec' :: [Char] -> Maybe Int
octoDec' s = fmap horner (parseString' s) -- or octoDec = fmap horner . parseString'

How do I use ORD and CHR with only A to Z and 0 to 9?

I'm trying to write a Caesar cipher but with only uppercase alphanumeric. Using ord or chr uses the whole ASCII table. How can accomplish this?
This is what I have so far:
alphabet = ['A'..'Z'] ++ ['0'..'9']
c2I = ord c - ord 'A'
i2C = chr (n + ord 'A')
the basic idea is to use mod to wrap around to the beginning.
Now it's not efficient (but hey you are using the most unsecure cipher so you might not care to much) but I'll show you using just the alphabet and indexing functions:
import Data.List (elemIndex)
alphabet :: [Char]
alphabet = ['A'..'Z'] ++ ['0'..'9']
ith :: Int -> Char
ith i = alphabet !! j
where j = i `mod` length alphabet
index :: Char -> Int
index c = case c `elemIndex` alphabet of
Just i -> i
Nothing -> error "not inalphabet"
encode :: Int -> String -> String
encode n xs = [ ith $ index x + n | x <- xs ]
this will give you
λ> encode 3 "ABCXYZ012789"
"DEF012345ABC"
now you probably will want to find a way using ord and chr - both works if you make a case distinction between A-Z and 0-9, because the ranges are:
65-90 for A-Z
48-57 for 0-9
so you cannot take a one formula without to many tricks
You should try but it's more math from here (you'll probably want something like ord c - ord 'A' for letters and 26 + ord c - ord '0' for digits to get it in the range 0-35 first.

Haskell "abc123de45" to [123,45]

From a String like "abc123def45" i want to get -> [123, 45].
I have the following now:
getDecimals :: String -> [Int]
getDecimals xs = [ digitToInt x | x<-xs , isDigit x]
Only this method is returning -> [1,2,3,4,5].
How can i do this?
Tnx!
If you are using Data.List.Split you can do this.
import Data.List.Split
import Data.Char
getDecimals :: String -> [Int]
getDecimals = map read . wordsBy (not . isDigit)
Here is a (quite long) on-liner to do this:
import Data.List
import Data.Char
getDecimals = ((map (read::String->Int)).(filter (isNumber.head)).(groupBy (\a b -> (isNumber a) && (isNumber b))))
Now let's break it down:
(
( map (read::String->Int) ). -- Go over the list of numerical strings and read them as Ints
( filter (isNumber.head) ). -- Filter out the strings which are not begining with digit
( groupBy -- Split the given list based on the following comparison function:
(\a b -> (isNumber a) && (isNumber b)) -- The comparison function to return true if both arguments are digits
)
)
Since we are using the . function, which is function composition, the functions above are applied in the order bottom to top to the given argument list. I am pretty sure there is more elegant ways to do this, but I can't think of any at this moment.
I've never played with regex-applicative before, so I guess I'll give it a go!
NOTE: the cleanest version, but the least interesting, is way down at the bottom.
The first version here is written to use just one regular expression, which means it's not at all lazy (oy!).
import Text.Regex.Applicative
import Data.Char
fakeDigitToInt :: Char -> Int
fakeDigitToInt x = ord x - ord '0'
digit = fakeDigitToInt <$> psym isDigit
addDigit big small = 10*big+small
number = addDigit <$> reFoldl Greedy addDigit 0 digit <*> digit
spacers = many (psym $ not . isDigit)
numbersInCrud = many (spacers *> number) <* spacers
readNumbersFromCrud = maybe [] id . match numbersInCrud
To make a lazy version, it's necessary to break things up a bit more, using more features of the parsing system. While I'm at it, I'll fix up the types a bit:
import Text.Regex.Applicative
import Data.Char
import Data.List (unfoldr)
fakeDigitToInt :: Char -> Int
fakeDigitToInt x = ord x - ord '0'
digit :: Num n => RE Char n
digit = fromIntegral . fakeDigitToInt <$> psym isDigit
addDigit big small = 10*big+small
number :: Num n => RE Char n
number = addDigit <$> reFoldl Greedy addDigit 0 digit <*> digit
spacers = many (psym $ not . isDigit)
pullNumber :: Num n => String -> Maybe (n, String)
pullNumber = findLongestPrefix (spacers *> number)
readNumbersFromCrud :: Num n => String -> [n]
readNumbersFromCrud = unfoldr pullNumber
The cleanest version
This is kind of boring, but it is simple:
import Text.Regex.Applicative
import Text.Regex.Applicative.Common
import Data.Char
import Data.List (unfoldr)
spacers = many (psym $ not . isDigit)
pullNumber :: Num n => String -> Maybe (n, String)
pullNumber = findLongestPrefix (spacers *> decimal)
readNumbersFromCrud :: Num n => String -> [n]
readNumbersFromCrud = unfoldr pullNumber
And because I couldn't resist, here's the (almost) one-liner:
import Text.Regex.Applicative
import Text.Regex.Applicative.Common
import Data.Char
import Data.List (unfoldr)
readNumbersFromCrud :: Num n => String -> [n]
readNumbersFromCrud = unfoldr . findLongestPrefix $
many (psym $ not . isDigit) *> decimal

Getting an integer from the console

Is there a way to read an integer from the console in Haskell? I'm asking for something pretty much like C++'s cin or Java's Scanner.nextInt().
And by that I mean that given this input:
1 2 3
2 3
4 25 12 7
1
I should be able to read them all, not at the same time (maybe reading 4 of them, doing some calculations and then read the rest) ignoring the fact that they are in separate lines.
The easiest solution is probably
getAll :: Read a => IO [a]
getAll = fmap (fmap read . words) getContents
getInts :: IO [Int]
getInts = getAll
which will read all input into a single list.
When in doubt, use Parsec! (not always, and not really, but who cares)
import Text.ParserCombinators.Parsec
import Text.Parsec.Numbers
value = do
spaces
num <- parseFloat
return num
line = many value
then "rinse and repeat", with getLine until you EOF.
Note: you can do it without Parsec using read and friends, but this way is more extendable and preferred for more complicated grammars.
Using Parsec:
import Text.ParserCombinators.Parsec
import Text.Parsec.Numbers
import Control.Applicative ((*>), (<*))
line = spaces *> many1 (parseFloat <* spaces)
main = putStrLn "Enter numbers:" >> fmap (parse line "") getLine >>= print
Running it:
$ ghc parsenums.hs
$ ./parsenums
Enter numbers:
345 23 654 234
[345.0,23.0,654.0,234.0]
A more "manual" way to do it would be something like:
import Data.Char (isDigit, isSpace)
getInts :: String -> [Int]
getInts s = case span isDigit (dropWhile isSpace s) of
("", "") -> []
("", s) -> error $ "Invalid input: " ++ s
(digits, rest) -> (read digits :: Int) : getInts rest
Which might be much clearer to see how it works. In fact, here's one that's completely from the ground up:
getInts :: String -> [Int]
getInts s = case span isDigit (dropWhile isSpace s) of
("", "") -> []
("", s) -> error $ "Invalid input: " ++ s
(digits, rest) -> strToInt digits : getInts rest
isDigit :: Char -> Bool
isDigit c = '0' <= c && c <= '9'
isSpace :: Char -> Bool
isSpace c = c `elem` " \t\n\r"
charToInt :: Char -> Int
charToInt c = fromEnum c - 48
strToInt :: String -> Int
strToInt s = go 0 s where
go n [] = n
go n (c:rest) = go (n * 10 + charToInt c) rest

How to write a function to modify a Char list and return it in Haskell?

Modification may well be just an addition of 3 to the Char ascii value.
I have gone through several books and can't find a solution off the shelf.
(Returning the Char list can be to a different list variable.)
import Data.Char
shiftAscii :: String -> String
shiftAscii xs = map (chr.(+3).ord) xs
would do what you ask.
It works because map edits each character in the string using the supplied function.
ord converts the Char to its Int value
(+3) shifts the (ascii) by 3
chr converts back to a Char,
so chr.(+3).ord is those three strung together with function composition .
To be more flexible, you could write
shiftAsciiBy :: Int -> String -> String
shiftAsciiBy n = map (chr.(+ n).ord)
notice that shifting the ascii doesn't respect alphabet boundaries, so if you were needing this to do rot13 encoding or similar simple shift, you'd be better off with a hand-rolled shift function that only edits the alphabet
addAscii :: Int -> Char -> Char
addAscii n c | isUpper c = chr $ ((ord c - ord 'A' + n) `mod` 26) + ord 'A'
| isLower c = chr $ ((ord c - ord 'a' + n) `mod` 26) + ord 'a'
| otherwise = c
for example
['A'..'z']
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz"
and we shift just the alphabet ascii:
map (addAscii 5) ['A'..'z']
"FGHIJKLMNOPQRSTUVWXYZABCDE[\\]^_`fghijklmnopqrstuvwxyzabcde"

Resources