XORing strings in Haskell - string

I want to write a program that encrypts a text using XOR-cipher. That's what I have for now:
-- XORres 2 strings
stringXor :: String -> String -> String
stringXor s t = map chr $ zipWith xor (map ord s) (map ord t)
-- encryption and decryption
encDec :: String -> String -> String
encDec text key = stringXor (take (length text) (cycle key)) text
But the output of encDec "this is a test" "k" is
"\US\ETX\STX\CANK\STX\CANK\nK\US\SO\CAN\US"
while I was expecting something like 1f0302184b02184b0a4b1f0e181f4b.
What could be the problem here? I've searched similar questions but that wasn't very helpful.

stringXor s t = map chr $ zipWith xor (map ord s) (map ord t)
You map chr to the results of XOR. This results in characters for each ASCII value. To show the results as hexadecimal, you will need to find a different function to replace chr or write one yourself.
Side note: In cryptography, it is common to use Base64 notation to encode binary data instead of hex because it uses less characters (and therefore less memory or network bandwidth) to represent the same binary sequence.

You are getting 1f0302184b02184b0a4b1f0e181f4b:
> "\x1f\x03\x02\x18\x4b\x02\x18\x4b\x0a\x4b\x1f\x0e\x18\x1f\x4b"
"\US\ETX\STX\CANK\STX\CANK\nK\US\SO\CAN\USK"
...which is exactly the output you saw from encDec (up to what appears to be a simple copy-paste error in your expected output).

The problem is with the chr :: Int -> Char. This function converts an Int to the corresponding character, but not a hexadecimal representation of that number.
You can for example define a utility function with intToDigit :: Int -> Char:
import Data.Char(intToDigit)
toHex2 :: Int -> String
toHex2 h = map intToDigit [d, m]
where (d, m) = divMod h 16
Then we can implement the function as:
stringXor :: String -> String -> String
stringXor s t = concatMap toHex2 (zipWith xor (map ord s) (map ord t))
Or as #DanielWagner says:
import Data.Function(on)
stringXor :: String -> String -> String
stringXor s t = concatMap toHex2 (zipWith (xor `on` ord) s t)
This then gives us:
Prelude Data.Char Data.Bits> encDec "this is a test" "k"
"1f0302184b02184b0a4b1f0e181f"
Note that you do not need to use length here, in fact it is safer without length, you can just use cycle:
encDec :: String -> String -> String
encDec text key = stringXor (cycle key) text

Related

How to use Maybe base correctly?

I write a code to convert a string to be a list of Intger:
convert::String -> Maybe [Int]
convert (c:cs)
isDigit c = Just(c: (convert cs):[])
otherwise = Nothing
and it shows an error...
test.hs:15:26: error:
parse error on input ‘=’
Perhaps you need a 'let' in a 'do' block?
e.g. 'let x = 5' instead of 'x = 5'
Why is that so...
While there are other compile errors in your code, the reason you're getting the error message about the parse error is because you are not including the pipe character used in guards.
convert (c:cs)
| isDigit c = Just(c: (convert cs):[])
| otherwise = Nothing
There were several errors in your code. You need to try to convert each character, which gives a Maybe Int. Then you loop on the string using mapM inside the Maybe monad :
import Data.Char
convertChar :: Char -> Maybe Int
convertChar c = if isDigit c then Just $ ord c else Nothing
convert :: String -> Maybe [Int]
convert = mapM convertChar
Another way of looking at V. Semeria's answer is to use sequence (from the Traversable type class) with map:
import Data.Char -- for ord
convertChar :: Char -> Maybe Int
convertChar c = if isDigit c then Just $ ord c - 48 else Nothing
convert :: String -> Maybe [Int]
-- Start with String -> [Maybe Int], then convert
-- the [Maybe Int] to Maybe [Int]
convert = sequence . map convertChar
This is a common pattern, so Traversable also provides traverse, which in this case is equivalent to sequence . map.
convert :: Traversable t => t Char -> Maybe (t Int)
convert = traverse converChar
Some examples (most of the instances of Traversable available by default aren't very interesting, but various tree types can have instances).
> convert "123"
Just [1,2,3]
> convert (Just '1')
Just (Just 1)
> convert (True, '2')
Just (True, 2)
> convert (Right '1')
Just (Right 1)

Haskell: Elegant solution for integer parsing

I want to write a function that gets the first integer in a string, if the integer is at the beginning of the string and is followed by space or nothing.
For example, "12" and "12 kids" would be valid strings, but "12kids", "a12" are invalid.
This is my function:
getFirstInteger :: String -> Int
getFirstInteger [] = error "No integer"
getFirstInteger str
| dropWhile (Char.isNumber) str == [] = read str :: Int
| Char.isSpace $ head $ dropWhile (Char.isNumber) str = read (takeWhile (Char.isNumber) str) :: Int
| otherwise = error "No integer found"
The problem is that if the string is actually an integer, head will raise an exception, so that is why the first condition exists. Is there any elegant solution to this problem?
getFirstInteger :: String -> Int
getFirstInteger = read . head . words
words will split the String into a list of Strings, which were originally separated by whitespace. head will take the first (or error if the original string was empty), and read will parse the string as usual (and error if the first word wasn't a valid Int).
However, I prefer a variant that doesn't use error on empty Strings or unparseable ones, e.g.
import Text.Read (readMaybe)
getFirstInteger :: String -> Maybe Int
getFirstInteger [] = Nothing
getFirstInteger xs = readMaybe . head . words $ xs
One could write this completely point-free with listToMaybe from Data.Maybe, but that's probably an overkill:
import Data.Maybe (listToMaybe)
import Text.Read (readMaybe)
import Control.Monad ((>=>))
getFirstInteger :: String -> Maybe Int
getFirstInteger = listToMaybe . words >=> readMaybe
If you want to parse strings without using parser combinator libraries or any of the machinery in Text.Read, have a look at the functions break and span:
span :: (a -> Bool) -> [a] -> ([a], [a])
break :: (a -> Bool) -> [a] -> ([a], [a])
The nice thing is that both of these functions not only return what they match but also the remainder of the string allowing you to continue your parsing.
To solve your problem:
import Data.Char
getFirstInteger :: String -> Maybe Int
getFirstInteger str
let (digs, rest1) = span isDigit str
endsok = case rest1 of
[] -> True
(c:_) -> c == ' '
in
if not (null digs) && endsok
then Just (read digs)
else Nothing -- either no digits or doesn't end properly
This version does not allow a leading minus sign. This next version allows an optional leading minus sign for the integer:
getFirstInteger' str =
let (minus,rest1) = span (=='-') str
(digs, rest2) = span isDigit rest1
endsok = case rest2 of
[] -> True
(c:_) -> c == ' '
in
if length minus <= 1 && not (null digs) && endsok
then Just (read (minus ++ digs))
else Nothing
Yes - this does not terminate as early as possible on bad input. I provide it mainly as an example of how to chain together calls to span and break.
Use reads. For example:
type Unit = String
readUnit :: String -> Maybe (Int, Maybe Unit)
readUnit s = case reads s of -- the integer is at the beginning of the string and...
(n, ' ':unit):_ -> Just (n, Just unit) -- is followed by space...
(n, "" ):_ -> Just (n, Nothing) -- or nothing.
_ -> Nothing
In ghci:
> readUnit "12"
Just (12,Nothing)
> readUnit "12 kids"
Just (12,Just "kids")
> readUnit "12kids"
Nothing
> readUnit "a12"
Nothing
However, there are a few minor considerations to keep in mind. It's possible that read does not restrict the syntax as much as you might want; for example, the following answer may surprise you:
> readUnit " ((-0x5)) kids"
Just (-5,Just "kids")
You may also want to drop extraneous spaces in the unit; for example, you could change the first clause above to
(n, ' ':unit):_ -> Just (n, Just (dropWhile isSpace unit))
or similar. And as a final variation on this theme, note that while the standard instances of Read never return lists with more than one element from reads, it is technically possible that some user-supplied type may do so. So if you were ever to use reads to parse types other than Int, you may want to either demand an unambiguous parse or consider all the parses before deciding what to do; the above code bakes in the assumption that the first parse is as good as any.

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"

How can I use map in this case

I have the code which create Data.Map:
import qualified Data.Map as Map
shift_string :: [Char] -> Int -> [Char]
shift_string s num = (drop num s) ++ (take num s)
ascii :: [Char]
ascii = ['a' .. 'z']
shifted_ascii :: Int -> [Char]
shifted_ascii n = shift_string ascii n
trans_table :: Int -> Map.Map Char Char
trans_table n = Map.fromList(zip ascii $ shifted_ascii n)
The 'trans_table' function returns the Map where one Char map to another map.
I can create the function to get one Char and return another one based on this Map:
translate_char :: Char -> Int -> Maybe Char
translate_char c n = Map.lookup c $ trans_table n
Now I want to 'translate' each symbol in the map. Something like this:
encode message key = map translate_char message
This code doesn't work as translate_function must have only one parameter. I need something like global variable to store the Map in it and lookup values from it in my map-function. But I don't know how to rewrite my code.
p.s. I guess I can just add 'key' to each char in my string but I am searching common solution.
I don't know whats key in your encode function but you can use something like
translate_char :: Int -> Char -> Maybe Char
translate_char n c = Map.lookup c $ trans_table n
encode :: Int -> String -> String
encode n s = catMaybes $ map (translate_char n) s
here n determines the number of characters you are rotating. I switched the order of parameters to avoid using flip.

What can be improved on my first haskell program?

Here is my first Haskell program. What parts would you write in a better way?
-- Multiplication table
-- Returns n*n multiplication table in base b
import Text.Printf
import Data.List
import Data.Char
-- Returns n*n multiplication table in base b
mulTable :: Int -> Int -> String
mulTable n b = foldl (++) (verticalHeader n b w) (map (line n b w) [0..n])
where
lo = 2* (logBase (fromIntegral b) (fromIntegral n))
w = 1+fromInteger (floor lo)
verticalHeader :: Int -> Int -> Int -> String
verticalHeader n b w = (foldl (++) tableHeader columnHeaders)
++ "\n"
++ minusSignLine
++ "\n"
where
tableHeader = replicate (w+2) ' '
columnHeaders = map (horizontalHeader b w) [0..n]
minusSignLine = concat ( replicate ((w+1)* (n+2)) "-" )
horizontalHeader :: Int -> Int -> Int -> String
horizontalHeader b w i = format i b w
line :: Int -> Int -> Int -> Int -> String
line n b w y = (foldl (++) ((format y b w) ++ "|" )
(map (element b w y) [0..n])) ++ "\n"
element :: Int -> Int -> Int -> Int -> String
element b w y x = format (y * x) b w
toBase :: Int -> Int -> [Int]
toBase b v = toBase' [] v where
toBase' a 0 = a
toBase' a v = toBase' (r:a) q where (q,r) = v `divMod` b
toAlphaDigits :: [Int] -> String
toAlphaDigits = map convert where
convert n | n < 10 = chr (n + ord '0')
| otherwise = chr (n + ord 'a' - 10)
format :: Int -> Int -> Int -> String
format v b w = concat spaces ++ digits ++ " "
where
digits = if v == 0
then "0"
else toAlphaDigits ( toBase b v )
l = length digits
spaceCount = if (l > w) then 0 else (w-l)
spaces = replicate spaceCount " "
Here are some suggestions:
To make the tabularity of the computation more obvious, I would pass the list [0..n] to the line function rather than passing n.
I would further split out the computation of the horizontal and vertical axes so that they are passed as arguments to mulTable rather than computed there.
Haskell is higher-order, and almost none of the computation has to do with multiplication. So I would change the name of mulTable to binopTable and pass the actual multiplication in as a parameter.
Finally, the formatting of individual numbers is repetitious. Why not pass \x -> format x b w as a parameter, eliminating the need for b and w?
The net effect of the changes I am suggesting is that you build a general higher-order function for creating tables for binary operators. Its type becomes something like
binopTable :: (i -> String) -> (i -> i -> i) -> [i] -> [i] -> String
and you wind up with a much more reusable function—for example, Boolean truth tables should be a piece of cake.
Higher-order and reusable is the Haskell Way.
You don't use anything from import Text.Printf.
Stylistically, you use more parentheses than necessary. Haskellers tend to find code more readable when it's cleaned of extraneous stuff like that. Instead of something like h x = f (g x), write h = f . g.
Nothing here really requires Int; (Integral a) => a ought to do.
foldl (++) x xs == concat $ x : xs: I trust the built-in concat to work better than your implementation.
Also, you should prefer foldr when the function is lazy in its second argument, as (++) is – because Haskell is lazy, this reduces stack space (and also works on infinite lists).
Also, unwords and unlines are shortcuts for intercalate " " and concat . map (++ "\n") respectively, i.e. "join with spaces" and "join with newlines (plus trailing newline)"; you can replace a couple things by those.
Unless you use big numbers, w = length $ takeWhile (<= n) $ iterate (* b) 1 is probably faster. Or, in the case of a lazy programmer, let w = length $ toBase b n.
concat ( (replicate ((w+1)* (n+2)) "-" ) == replicate ((w+1) * (n+2)) '-' – not sure how you missed this one, you got it right just a couple lines up.
You do the same thing with concat spaces, too. However, wouldn't it be easier to actually use the Text.Printf import and write printf "%*s " w digits?
Norman Ramsey gave excellent high-level (design) suggestions; Below are some low-level ones:
First, consult with HLint. HLint is a friendly program that gives you rudimentary advice on how to improve your Haskell code!
In your case HLint gives 7 suggestions. (mostly about redundant brackets)
Modify your code according to HLint's suggestions until it likes what you feed it.
More HLint-like stuff:
concat (replicate i "-"). Why not replicate i '-'?
Consult with Hoogle whenever there is reason to believe that a function you need is already available in Haskell's libraries. Haskell comes with tons of useful functions so Hoogle should come in handy quite often.
Need to concatenate strings? Search for [String] -> String, and voila you found concat. Now go replace all those folds.
The previous search also suggested unlines. Actually, this even better suits your needs. It's magic!
Optional: pause and thank in your heart to Neil M for making Hoogle and HLint, and thank others for making other good stuff like Haskell, bridges, tennis balls, and sanitation.
Now, for every function that takes several arguments of the same type, make it clear which means what, by giving them descriptive names. This is better than comments, but you can still use both.
So
-- Returns n*n multiplication table in base b
mulTable :: Int -> Int -> String
mulTable n b =
becomes
mulTable :: Int -> Int -> String
mulTable size base =
To soften the extra characters blow of the previous suggestion: When a function is only used once, and is not very useful by itself, put it inside its caller's scope in its where clause, where it could use the callers' variables, saving you the need to pass everything to it.
So
line :: Int -> Int -> Int -> Int -> String
line n b w y =
concat
$ format y b w
: "|"
: map (element b w y) [0 .. n]
element :: Int -> Int -> Int -> Int -> String
element b w y x = format (y * x) b w
becomes
line :: Int -> Int -> Int -> Int -> String
line n b w y =
concat
$ format y b w
: "|"
: map element [0 .. n]
where
element x = format (y * x) b w
You can even move line into mulTable's where clause; imho, you should.
If you find a where clause nested inside another where clause troubling, then I suggest to change your indentation habits. My recommendation is to use consistent indentation of always 2 or always 4 spaces. Then you can easily see, everywhere, where the where in the other where is at. ok
Below's what it looks like (with a few other changes in style):
import Data.List
import Data.Char
mulTable :: Int -> Int -> String
mulTable size base =
unlines $
[ vertHeaders
, minusSignsLine
] ++ map line [0 .. size]
where
vertHeaders =
concat
$ replicate (cellWidth + 2) ' '
: map horizontalHeader [0 .. size]
horizontalHeader i = format i base cellWidth
minusSignsLine = replicate ((cellWidth + 1) * (size + 2)) '-'
cellWidth = length $ toBase base (size * size)
line y =
concat
$ format y base cellWidth
: "|"
: map element [0 .. size]
where
element x = format (y * x) base cellWidth
toBase :: Integral i => i -> i -> [i]
toBase base
= reverse
. map (`mod` base)
. takeWhile (> 0)
. iterate (`div` base)
toAlphaDigit :: Int -> Char
toAlphaDigit n
| n < 10 = chr (n + ord '0')
| otherwise = chr (n + ord 'a' - 10)
format :: Int -> Int -> Int -> String
format v b w =
spaces ++ digits ++ " "
where
digits
| v == 0 = "0"
| otherwise = map toAlphaDigit (toBase b v)
spaces = replicate (w - length digits) ' '
0) add a main function :-) at least rudimentary
import System.Environment (getArgs)
import Control.Monad (liftM)
main :: IO ()
main = do
args <- liftM (map read) $ getArgs
case args of
(n:b:_) -> putStrLn $ mulTable n b
_ -> putStrLn "usage: nntable n base"
1) run ghc or runhaskell with -Wall; run through hlint.
While hlint doesn't suggest anything special here (only some redundant brackets), ghc will tell you that you don't actually need Text.Printf here...
2) try running it with base = 1 or base = 0 or base = -1
If you want multiline comments use:
{- A multiline
comment -}
Also, never use foldl, use foldl' instead, in cases where you are dealing with large lists which must be folded. It is more memory efficient.
A brief comments saying what each function does, its arguments and return value, is always good. I had to read the code pretty carefully to fully make sense of it.
Some would say if you do that, explicit type signatures may not be required. That's an aesthetic question, I don't have a strong opinion on it.
One minor caveat: if you do remove the type signatures, you'll automatically get the polymorphic Integral support ephemient mentioned, but you will still need one around toAlphaDigits because of the infamous "monomorphism restriction."

Resources