Replacing characters with numbers in Haskell - string

I have started to do the questions on Project Euler regarding lists of names which need to be replaced with their corresponding position in the alphabet. In Problem 22 I need to replace, the letters with numbers:
names = ["MARY","PATRICIA","LINDA"....
replace = ??????
char2num a = map replace a
score (a,b) = a * (sum $ map char2num b)
answer = sum $ map score (zip [1..] (sort names))
What I cannot find is how to replace the characters with their place in the alphabet. How would I go about making something to do the replace function (preferably not regex)?

The ord function in the Data.Char module gives an integer code for each character. Given that, this would be the function you're looking for:
import Data.Char
replace :: Char -> Int
replace c = ord c - ord 'A' + 1
I'm not sure if ord c will return the ASCII code for a character, or the unicode codepoint, or if the result is machine dependent. To abstract from that, we simply subtract the code for 'A' from the result, and add 1 because we want the alphabet to start at 1 instead of 0.
An easy way to find to find such a function is Hoogle.
There you can search for functions in the standard Haskell packages by entering its type. In this case ord is the second result when searching for Char -> Int.

Related

Padding an empty string to text

I am do a crypto exercise that I need to pad an input text to have length of multiple of 16 bytes (AES), and I find that in python I can create a empty (i.e. string of space) with:
' ' * n # whatever integer n is
Is there an equivalent way in haskell? I can do it with simple function using recursion, but just curious is there a way that is even shorter than the python snip.
Since strings are lists of characters, you can use:
replicate :: Int -> a -> [a]
For example:
replicate 5 'x' == "xxxxx"
You can find utility functions like this yourself by searching for a plausible type signature with Hoogle; replicate happens to be the first result in a Hoogle search for Int -> a -> [a].
If you’re using Text instead of String, there is an equivalent function in Data.Text:
replicate :: Int -> Text -> Text
replicate 5 (pack "x") == pack "xxxxx"

Why am I receiving this syntax error - possibly due to bad layout?

I've just started trying to learn haskell and functional programming. I'm trying to write this function that will convert a binary string into its decimal equivalent. Please could someone point out why I am constantly getting the error:
"BinToDecimal.hs":19 - Syntax error in expression (unexpected `}', possibly due to bad layout)
module BinToDecimal where
total :: [Integer]
total = []
binToDecimal :: String -> Integer
binToDecimal a = if (null a) then (sum total)
else if (head a == "0") then binToDecimal (tail a)
else if (head a == "1") then total ++ (2^((length a)-1))
binToDecimal (tail a)
So, total may not be doing what you think it is. total isn't a mutable variable that you're changing, it will always be the empty list []. I think your function should include another parameter for the list you're building up. I would implement this by having binToDecimal call a helper function with the starting case of an empty list, like so:
binToDecimal :: String -> Integer
binToDecimal s = binToDecimal' s []
binToDecimal' :: String -> [Integer] -> Integer
-- implement binToDecimal' here
In addition to what #Sibi has said, I would highly recommend using pattern matching rather than nested if-else. For example, I'd implement the base case of binToDecimal' like so:
binToDecimal' :: String -> [Integer] -> Integer
binToDecimal' "" total = sum total -- when the first argument is the empty string, just sum total. Equivalent to `if (null a) then (sum total)`
-- Include other pattern matching statements here to handle your other if/else cases
If you think it'd be helpful, I can provide the full implementation of this function instead of giving tips.
Ok, let me give you hints to get you started:
You cannot do head a == "0" because "0" is String. Since the type of a is [Char], the type of head a is Char and you have to compare it with an Char. You can solve it using head a == '0'. Note that "0" and '0' are different.
Similarly, rectify your type error in head a == "1"
This won't typecheck: total ++ (2^((length a)-1)) because the type of total is [Integer] and the type of (2^((length a)-1)) is Integer. For the function ++ to typecheck both arguments passed to it should be list of the same type.
You are possible missing an else block at last. (before the code binToDecimal (tail a))
That being said, instead of using nested if else expression, try to use guards as they will increase the readability greatly.
There are many things we can improve here (but no worries, this is perfectly normal in the beginning, there is so much to learn when we start Haskell!!!).
First of all, a string is definitely not an appropriate way to represent a binary, because nothing prevents us to write "éaldkgjasdg" in place of a proper binary. So, the first thing is to define our binary type:
data Binary = Zero | One deriving (Show)
We just say that it can be Zero or One. The deriving (Show) will allow us to have the result displayed when run in GHCI.
In Haskell to solve problem we tend to start with a more general case to dive then in our particular case. The thing we need here is a function with an additional argument which holds the total. Note the use of pattern matching instead of ifs which makes the function easier to read.
binToDecimalAcc :: [Binary] -> Integer -> Integer
binToDecimalAcc [] acc = acc
binToDecimalAcc (Zero:xs) acc = binToDecimalAcc xs acc
binToDecimalAcc (One:xs) acc = binToDecimalAcc xs $ acc + 2^(length xs)
Finally, since we want only to have to pass a single parameter we define or specific function where the acc value is 0:
binToDecimal :: [Binary] -> Integer
binToDecimal binaries = binToDecimalAcc binaries 0
We can run a test in GHCI:
test1 = binToDecimal [One, Zero, One, Zero, One, Zero]
> 42
OK, all fine, but what if you really need to convert a string to a decimal? Then, we need a function able to convert this string to a binary. The problem as seen above is that not all strings are proper binaries. To handle this, we will need to report some sort of error. The solution I will use here is very common in Haskell: it is to use "Maybe". If the string is correct, it will return "Just result" else it will return "Nothing". Let's see that in practice!
The first function we will write is to convert a char to a binary. As discussed above, Nothing represents an error.
charToBinary :: Char -> Maybe Binary
charToBinary '0' = Just Zero
charToBinary '1' = Just One
charToBinary _ = Nothing
Then, we can write a function for a whole string (which is a list of Char). So [Char] is equivalent to String. I used it here to make clearer that we are dealing with a list.
stringToBinary :: [Char] -> Maybe [Binary]
stringToBinary [] = Just []
stringToBinary chars = mapM charToBinary chars
The function mapM is a kind of variation of map which acts on monads (Maybe is actually a monad). To learn about monads I recommend reading Learn You a Haskell for Great Good!
http://learnyouahaskell.com/a-fistful-of-monads
We can notice once more that if there are any errors, Nothing will be returned.
A dedicated function to convert strings holding binaries can now be written.
binStringToDecimal :: [Char] -> Maybe Integer
binStringToDecimal = fmap binToDecimal . stringToBinary
The use of the "." function allow us to define this function as an equality with another function, so we do not need to mention the parameter (point free notation).
The fmap function allow us to run binToDecimal (which expect a [Binary] as argument) on the return of stringToBinary (which is of type "Maybe [Binary]"). Once again, Learn you a Haskell... is a very good reference to learn more about fmap:
http://learnyouahaskell.com/functors-applicative-functors-and-monoids
Now, we can run a second test:
test2 = binStringToDecimal "101010"
> Just 42
And finally, we can test our error handling system with a mistake in the string:
test3 = binStringToDecimal "102010"
> Nothing

Haskell - Returning the number of a-Z characters used in a string

I've been using this page on the Haskell website all day and its been really helpful with learning list functions: http://www.haskell.org/haskellwiki/How_to_work_on_lists
My task at the moment is to write a single line statement that returns the number of characters (a-Z) that are used in a string. I can't seem to find any help on the above page or anywhere else on the internet
I know how to count characters in a string by using length nameoflist, but I'm not sure how I would go about counting the number of a-Z characters that have been used, for example 'starT to' should return 6
Any help is appreciated, thanks
An alternative to #Sibi's perfectly fine answer is to use a combination of sort and group from Data.List:
numUnique :: Ord a => [a] -> Int
numUnique = length . group . sort
This imposes the tighter restriction of Ord instead of just Eq, but I believe might be somewhat faster since nub is not known for its efficiency. You can also use a very similar function to count the number of each unique element in the list:
elemFrequency :: Ord a => [a] -> [(a, Int)]
elemFrequency = map (\s -> (head s, length s)) . group . sort
Or if you want to use the more elegant Control.Arrow form
elemFrequency = map (head &&& length) . group . sort
It can be used as
> elemFrequency "hello world"
[(' ',1),('d',1),('e',1),('h',1),('l',3),('o',2),('r',1),('w',1)]
You can remove the duplicate elements using nub and find the length of the resulting list.
import Data.List (nub)
numL :: Eq a => [a] -> Int
numL xs = length $ nub xs
Demo in ghci:
ghci > numL "starTto"
6
In case you don't want to consider a whitespace in the String, then remove it using a filter or any other appropriate function.
There are a few ways to do this, depending on what structure you want to use.
If you want to use Eq structure, you can do this with nub. If the inputs denote a small set of characters, then this is fairly good. However, if there are a lot of distinct alphabetic characters (remember that "Å" and "Ω" are both alphabetic, according to isAlpha), then this technique will have poor performance (quadratic running time).
import Data.Char (isAlpha)
import Data.List (nub)
distinctAlpha :: String -> Int
distinctAlpha = length . nub . filter isAlpha
You can increase performance for larger sets of alphabetic characters by using additional structure. Ord is the first choice, and allows you to use Data.Set, which gives O(N log N) asymptotic performance.
import Data.Char (isAlpha)
import Data.Set (size, fromList)
distinctAlpha :: String -> Int
distinctAlpha = size . fromList . filter isAlpha
First, filter the list in order to remove any non a-Z characters; second, remove duplicate elements; third, calculate its length.
import Data.Char (isAlpha)
import Data.List (nub)
count = length . nub . filter isAlpha
numberOfCharacters = length . Data.List.nub . filter Data.Char.isAlpha

First attempt at Haskell: Converting lower case letters to upper case

I have recently started learning Haskell, and I've tried creating a function in order to convert a lower case word to an upper case word, it works, but I don't know how good it is and I have some questions.
Code:
lowerToUpperImpl element list litereMari litereMici =
do
if not (null list) then
if (head list) == element then
['A'..'Z'] !! (length ['A'..'Z'] - length (tail list ) -1)
else
lowerToUpperImpl element (tail list) litereMari litereMici
else
'0' --never to be reached
lowerToUpper element = lowerToUpperImpl element ['a'..'z'] ['A'..'Z'] ['a'..'z']
lowerToUpperWordImpl word =
do
if not (null word) then
lowerToUpper (head (word)):(lowerToUpperWordImpl (tail word))
else
""
I don't like the way I have passed the upper case and lower case
letters , couldn't I just declare a global variables or something?
What would your approach be in filling the dead else branch?
What would your suggestions on improving this be?
Firstly, if/else is generally seen as a crutch in functional programming languages, precisely because they aren't really supposed to be used as branch operations, but as functions. Also remember that lists don't know their own lengths in Haskell, and so calculating it is an O(n) step. This is particularly bad for infinite lists.
I would write it more like this (if I didn't import any libraries):
uppercase :: String -> String
uppercase = map (\c -> if c >= 'a' && c <= 'z' then toEnum (fromEnum c - 32) else c)
Let me explain. This code makes use of the Enum and Ord typeclasses that Char satisfies. fromEnum c translates c to its ASCII code and toEnum takes ASCII codes to their equivalent characters. The function I supply to map simply checks that the character is lowercase and subtracts 32 (the difference between 'A' and 'a') if it is, and leaves it alone otherwise.
Of course, you could always just write:
import Data.Char
uppercase :: String -> String
uppercase = map toUpper
Hope this helps!
The things I always recommend to people in your circumstances are these:
Break the problem down into smaller pieces, and write separate functions for each piece.
Use library functions wherever you can to solve the smaller subproblems.
As an exercise after you're done, figure out how to write on your own the library functions you used.
In this case, we can apply the points as follows. First, since String in Haskell is a synonym for [Char] (list of Char), we can break your problem into these two pieces:
Turn a character into its uppercase counterpart.
Transform a list by applying a function separately to each of its members.
Second point: as Alex's answer points out, the Data.Char standard library module comes with a function toUpper that performs the first task, and the Prelude library comes with map which performs the second. So using those two together solves your problem immediately (and this is exactly the code Alex wrote earlier):
import Data.Char
uppercase :: String -> String
uppercase = map toUpper
But I'd say that this is the best solution (shortest and clearest), and as a beginner, this is the first answer you should try.
Applying my third point: after you've come up with the standard solution, it is enormously educational to try and write your own versions of the library functions you used. The point is that this way you learn three things:
How to break down problems into easier, smaller pieces, preferably reusable ones;
The contents of the standard libraries of the language;
How to write the simple "foundation" functions that the library provides.
So in this case, you can try writing your own versions of toUpper and map. I'll provide a skeleton for map:
map :: (a -> b) -> [a] -> [b]
map f [] = ???
map f (x:xs) = ???

Find and replace in Haskell

I want to input a list of 2 element lists of characters (just letters) where the first element is a letter in a String (the second argument for findAndReplace) and the second is what I want it changed to. Is there already a function in Haskell that does a similar thing? Because this would help greatly!
It sounds more like you might want to use a list of tuples instead of a list of lists for your first input, since you specify a fixed length. Tuples are fixed-length collections that can have mixed types, while lists are arbitrary-length collections of a single type:
myTuple = ('a', 'b') :: (Char, Char)
myTriple = ('a', 'b', 'c') :: (Char, Char, Char)
myList = ['a'..'z'] :: [Char]
Notice how I have to specify the type of each field of the tuples. Also, (Char, Char) is not the same type as (Char, Char, Char), they are not compatible.
So, with tuples, you can have your type signature for replace as:
replace :: [(Char, Char)] -> String -> String
And now this specifies with the type signature that it has to be a list of pairs of characters to find and replace, you won't have to deal with bad input, like if someone only gave a character to search for but not one to replace it with.
We now are passing in what is commonly referred to as an association list, and Haskell even has some built in functions for dealing with them in Data.List and Data.Map. However, for this exercise I don't think we'll need it.
Right now you're wanting to solve this problem using a list of pairs, but it'd be easier if we solved it using just one pair:
replace1 :: (Char, Char) -> String -> String
replace1 (findChr, replaceChr) text = ?
Now, you want to check each character of text and if it's equal to findChr, you want to replace it with replaceChr, otherwise leave it alone.
replace1 (findChr, replaceChr) text = map (\c -> ...) text
I'll let you fill in the details (hint: if-then-else).
Then, you can use this to build your replace function using the simpler replace1 function. This should get you started, and if you still can't figure it out after a day or two, comment below and I'll give you another hint.

Resources