Convert string of whitespace separated numbers in a string into integers and place them in variables - haskell

I'm trying to write a function(s) to accept a string of 4 whitespace separated numbers in a string, separate and convert them to integers, and place them in 4 individual integer variables. I know I can use splitWs to split them into a string array, use !! to access the individual elements, and something like the following to convert to integer:
f :: [String] -> [Int]
f = map read
But I can't figure out how to put it all together.

Use the words function to split the string by whitespace. Then you can map read over the result.
Thus, a simple implementation would be:
readNumbers :: String -> [Int]
readNumbers = map read . words
Then, if you need exactly four numbers, use pattern matching:
case readNumbers string of
[a,b,c,d] -> ...
_ -> error "Expected four numbers"

There are no variables in Haskell, in Haskell strings are represented as lists. So
try:
import Data.List.Utils
nums=map read $split " " "1 2 3 4" :: [Int]
You can access the single elements with (!!):
> nums(!!)0
1
HTH Chris

Related

How to convert a string to an array containing each character in Haskell?

I was looking at this post here:
Haskell get character array from string?
I see it says that in haskell strings are essentially arrays containing each letter, but I was wondering; how would I turn the format from the string to an array of individual components, for example:
["ABCD","EFGH"]
to
[["A","B","C","D"],["E","F","G","H"]]
I'd like to know a method without using any external imports.
You can wrap each element in a singleton list, so:
map (map pure) ["ABCD", "EFGH"] :: [[String]]
this then produces:
Prelude> map (map pure) ["ABCD", "EFGH"] :: [[String]]
[["A","B","C","D"],["E","F","G","H"]]
That being said, a String is simply a list of Chars, indeed:
type String = [Char]
so if you just want to work with a list of Chars, you can simply work with the string directly. By converting it to a list of list of Strings, we know that all these strings contain one Char, but that is no longer guaranteed by the type.

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"

converting a list of string into a list of tuples in Haskell

I have a list of strings:
[" ix = index"," ctr = counter"," tbl = table"]
and I want to create a tuple from it like:
[("ix","index"),("ctr","counter"),("tbl","table")]
I even tried:
genTuple [] = []
genTuples (a:as)= do
i<-splitOn '=' a
genTuples as
return i
Any help would be appriciated
Thank you.
Haskell's type system is really expressive, so I suggest to think about the problem in terms of types. The advantage of this is that you can solve the problem 'top-down' and the whole program can be typechecked as you go, so you can catch all kinds of errors early on. The general approach is to incrementally divide the problem into smaller functions, each of which remaining undefined initially but with some plausible type.
What you want is a function (let's call it convert) which take a list of strings and generates a list of tuples, i.e.
convert :: [String] -> [(String, String)]
convert = undefined
It's clear that each string in the input list will need to be parsed into a 2-tuple of strings. However, it's possible that the parsing can fail - the sheer type String makes no guarantees that your input string is well formed. So your parse function maybe returns a tuple. We get:
parse :: String -> Maybe (String, String)
parse = undefined
We can immediately plug this into our convert function using mapMaybe:
convert :: [String] -> [(String, String)]
convert list = mapMaybe parse list
So far, so good - but parse is literally still undefined. Let's say that it should first verify that the input string is 'valid', and if it is - it splits it. So we'll need
valid :: String -> Bool
valid = undefined
split :: String -> (String, String)
split = undefined
Now we can define parse:
parse :: String -> Maybe (String, String)
parse s | valid s = Just (split s)
| otherwise = Nothing
What makes a string valid? Let's say it has to contain a = sign:
valid :: String -> Bool
valid s = '=' `elem` s
For splitting, we'll take all the characters up to the first = for the first tuple element, and the rest for the second. However, you probably want to trim leading/trailing whitespace as well, so we'll need another function. For now, let's make it a no-op
trim :: String -> String
trim = id
Using this, we can finally define
split :: String -> (String, String)
split s = (trim a, trim (tail b))
where
(a, b) = span (/= '=') s
Note that we can safely call tail here because we know that b is never empty because there's always a separator (that's what valid verified). Type-wise, it would've been nice to express this guarantee using a "non-empty string" but that may be a bit overengineered. :-)
Now, there are a lot of solutions to the problem, this is just one example (and there are ways to shorten the code using eta reduction or existing libraries). The main point I'm trying to get across is that Haskell's type system allows you to approach the problem in a way which is directed by types, which means the compiler helps you fleshing out a solution from the very beginning.
You can do it like this:
import Control.Monda
import Data.List
import Data.List.Split
map ((\[a,b] -> (a,b)) . splitOn "=" . filter (/=' ')) [" ix = index"," ctr = counter"," tbl = table"]

Haskell negating functions

This is my task:
Write a function:
onlyDigits :: String -> String
that strips all non-digit characters from a string (for example, onlyDigits "ac245d62"
is "24562").
I have this:
onlyDigits :: String -> String
onlyDigits a = [ (not)isAlpha b | b <- a ]
But i can't compile it
Can anyone see where i've gone wrong?
By writing
(not) isAlpha b
you're applying not to the two arguments isAlpha and b, and that's probably why the compiler complains.
If you fix this little mistake and now write:
onlyDigits :: String -> String
onlyDigits a = [ not (isAlpha b) | b <- a ]
you'll still get an error since this creates a list of Bools!
What you probably want is:
onlyDigits :: String -> String
onlyDigits a = [ b | b <- a, not $ isAlpha b ]
This will take all the elements b of a, that fulfil the condition not (isAlpha b).
You could also use the filter function and have a point-free function:
onlyDigits :: String -> String
onlyDigits = filter (not.isAlpha)
or even better:
onlyDigits :: String -> String
onlyDigits = filter isDigit
to only keep digits!
You actually have 2 errors.
The first one is a type error, stemming from not using function application correctly.
But the second one is that your function will still not do what you want if you only filter one category of unwanted characters. For example, you also do not want space characters. Or graphic symbols.
Sometimes, it is better to say "I want this" instead of "I want anything but ... (long list)".
So, filter for the property you want, not for the negation of one of the properties you don't want.

How can we split the list elements in new lines

I am still a beginer in Haskell and I want to know how can I split the numbers in a list in new lines so each line contains one element of the list.
If you have a [Char], a String, you may use the function lines that splits it... But I think what you're looking for is this:
as_lines l = unlines $ map show l
unlines :: [String] -> String concatenates the given Strings, using a newline as the connector. I hope this does what you want.

Resources