Combining multiple functions - haskell

I'm trying to make a DNA transcription program but I'm having trouble with the way I'm doing it, I'm sure there's an easier way to do this but this was the first thing that came to my head but it's not working the way I want it to.
dnaToRna :: [Char] -> [Char]
dnaToRna [] = []
dnaToRna xs = reverse(transc xs)
where transc = (replaceA . replaceT . replaceC . replaceG)
replaceA = map(\c -> if c == 'A' then 'U' else c)
replaceT = map(\c -> if c == 'T' then 'A' else c)
replaceC = map(\c -> if c == 'C' then 'G' else c)
replaceG = map(\c -> if c == 'G' then 'C' else c)
Here's the output:
*Main> let seq = "AAATGTTAGTACACTAAGG"
*Main> dnaToRna seq
"GGUUUGUGUUGUUUGUUUU"
I figure this is because the transc replaces the A, then checks the whole String and replaces the T, etc etc
Any tips?
Thanks in advance!

You should make one function which handles all of the Char -> Char conversions at once.
dnaToRna :: [Char] -> [Char]
dnaToRna = reverse . map transc
where
transc 'A' = 'U'
transc 'T' = 'A'
transc 'C' = 'G'
transc 'G' = 'C'
transc _ = error "Invalid DNA molecule"
To make this even safer, you could make it return a Maybe [Char] instead. The lookup function can also be used instead of using a custom mapping function.
dnaToRna :: [Char] -> Maybe [Char]
dnaToRna = mapM (`lookup` zip "ATCG" "UAGC") . reverse

#4castle's answer shows the right direction.
Since OP's problem has been solved i believe it would worth to show how to make it more efficient by using Data.Map for the look ups. Also by using a foldl we may skip the reversing job as well.
import qualified Data.Map.Lazy as M
dna2rna :: String -> String
dna2rna = foldl (\r c -> (M.findWithDefault '-' c m) : r) ""
where m = M.fromList $ zip "ATCG" "UAGC"
*Main> dna2rna "AAATGTTAGTACACTAAGG"
"CCUUAGUGUACUAACAUUU"

Related

counting lower and uppercase characters in 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

Haskell: Exception <<loop>> on recursive data entry

So I'm trying to make a little program that can take in data captured during an experiment, and for the most part I think I've figured out how to recursively take in data until the user signals there is no more, however upon termination of data taking haskell throws Exception: <<loop>> and I can't really figure out why. Here's the code:
readData :: (Num a, Read a) => [Point a] -> IO [Point a]
readData l = do putStr "Enter Point (x,y,<e>) or (d)one: "
entered <- getLine
if (entered == "d" || entered == "done")
then return l
else do let l = addPoint l entered
nl <- readData l
return nl
addPoint :: (Num a, Read a) => [Point a] -> String -> [Point a]
addPoint l s = l ++ [Point (dataList !! 0) (dataList !! 1) (dataList !! 2)]
where dataList = (map read $ checkInputData . splitOn "," $ s) :: (Read a) => [a]
checkInputData :: [String] -> [String]
checkInputData xs
| length xs < 2 = ["0","0","0"]
| length xs < 3 = (xs ++ ["0"])
| length xs == 3 = xs
| length xs > 3 = ["0","0","0"]
As far as I can tell, the exception is indication that there is an infinite loop somewhere, but I can't figure out why this is occurring. As far as I can tell when "done" is entered the current level should simply return l, the list it's given, which should then cascade up the previous iterations of the function.
Thanks for any help. (And yes, checkInputData will have proper error handling once I figure out how to do that.)
<<loop>> basically means GHC has detected an infinite loop caused by a value which depends immediately on itself (cf. this question, or this one for further technical details if you are curious). In this case, that is triggered by:
else do let l = addPoint l entered
This definition, which shadows the l you passed as an argument, defines l in terms of itself. You meant to write something like...
else do let l' = addPoint l entered
... which defines a new value, l', in terms of the original l.
As Carl points out, turning on -Wall (e.g. by passing it to GHC at the command line, or with :set -Wall in GHCi) would make GHC warn you about the shadowing:
<interactive>:171:33: warning: [-Wname-shadowing]
This binding for ‘l’ shadows the existing binding
bound at <interactive>:167:10
Also, as hightlighted by dfeuer, the whole do-block in the else branch can be replaced by:
readData (addPoint l entered)
As an unrelated suggestion, in this case it is a good idea to replace your uses of length and (!!) with pattern matching. For instance, checkInputData can be written as:
checkInputData :: [String] -> [String]
checkInputData xs = case xs of
[_,_] -> xs ++ ["0"]
[_,_,_] -> xs
_ -> ["0","0","0"]
addPoint, in its turn, might become:
addPoint :: (Num a, Read a) => [Point a] -> String -> [Point a]
addPoint l s = l ++ [Point x y z]
where [x,y,z] = (map read $ checkInputData . splitOn "," $ s) :: (Read a) => [a]
That becomes even neater if you change checkInputData so that it returns a (String, String, String) triple, which would better express the invariant that you are reading exactly three values.

Appending monad

With just putChar I can do stuff like this:
f =
do
putChar 'a'
putChar 'b'
g
putChar 'f'
putChar 'g'
g =
do
putChar 'c'
putChar 'd'
putChar 'e'
And what I will find when I "run" this (by saying main = f) it'll just print the characters out in order.
What I'm looking for is a non-IO version. Something that works a bit like this:
f =
do
append 'a'
append 'b'
g
append 'f'
append 'g'
g =
do
append 'c'
append 'd'
append 'e'
And a function, say runAppend :: t a -> [a]
Such that runAppend f = ['a','b','c','d','e','f','g']
Naturally I'd want this to run in linear time (i.e. not suffer issues like ++ does when you do the concatenations in a bad order).
This seems like a fairly common use case so I'm guessing it exists, if someone could point me to it that would be good, I didn't want to reinvent the wheel.
The Writer monad does this:
> let g = tell "b" >> tell "c" >> tell "d"
> runWriter (tell "a" >> g >> tell "e")
((),"abcde")
You can use a Writer monad for this:
import Control.Monad.Writer
import Data.DList (DList)
import qualified Data.DList as DList
type Append c = Writer (DList c)
append :: c -> Append c ()
append = tell . pure
runAppend :: Append c () -> [c]
runAppend = DList.toList . execWriter
f, g :: Append Char ()
This is a bit more complicated than necessary because it uses a DList Char instead of a String. DList gives you an efficient Monoid instance for this case where you keep appending to the end.

Does Maybe MonadPlus Parsers need to be in certain order?

Im working through the exercises on wikibooks/haskell and there is an exercise in the MonadPlus-chapter that wants you to write this hexChar function. My function works as shown below, but the thing is that when I try to switch the 2 helper parsers (digitParse and alphaParse) around the function ceases to work properly. If I switch them around I can only parse digits and not alphabetic chars anymore.
Why is this so?
char :: Char -> String -> Maybe (Char, String)
char c s = do
let (c':s') = s
if c == c' then Just (c, s') else Nothing
digit :: Int -> String -> Maybe Int
digit i s | i > 9 || i < 0 = Nothing
| otherwise = do
let (c:_) = s
if read [c] == i then Just i else Nothing
hexChar :: String -> Maybe (Char, String)
hexChar s = alphaParse s `mplus` digitParse s -- cannot switch these to parsers around!!
where alphaParse s = msum $ map ($ s) (map char (['a'..'f'] ++ ['A'..'F']))
digitParse s = do let (c':s') = s
x <- msum $ map ($ s) (map digit [0..9])
return (intToDigit x, s')
if read [c] == i then Just i else Nothing
The marked code has a flaw. You're using Int's Read instance, e.g. read :: String -> Int. But if it's not possible to parse [c] as an int (e.g. "a"), read will throw an exception:
> digit 1 "doesnt start with a digit"
*** Exception: Prelude.read: no parse
> -- other example
> (read :: String -> Int) "a"
*** Exception: Prelude.read: no parse
Instead, go the other way:
if [c] == show i then Just i else Nothing
This will always works, since show won't fail (not counting cases where bottom is involved).

Haskell replace characters in string

Supposing I had the string "HELLO WORLD" is there a way I can call a function that replaces the character 'O' in the string with the character 'X' so that the new string would look like "HELLX WXRLD"?
How about:
let
repl 'o' = 'x'
repl c = c
in map repl "Hello World"
If you need to replace additional characters later, just add clauses to the repl function.
Sorry for picking up this old thread but why not use lambda expressions?
λ> let replaceO = map (\c -> if c=='O' then 'X'; else c)
λ> replaceO "HELLO WORLD"
"HELLX WXRLD"`
Alternative 1 - Using MissingH
First:
import Data.List.Utils (replace)
Then use:
replace "O" "X" "HELLO WORLD"
Alternative 2 - Using Control.Monad
One funny bastard:
import Control.Monad (mfilter)
replace a b = map $ maybe b id . mfilter (/= a) . Just
Example:
λ> replace 'O' 'X' "HELLO WORLD"
"HELLX WXRLD"
Alternative 3 - Using if
Amon's suggestions was probably the finest I believe! No imports and easy to read and understand!
But to be picky - there's no need for semicolon:
replace :: Eq a => a -> a -> [a] -> [a]
replace a b = map $ \c -> if c == a then b else c
If you depend on the text package (like 99.99% of Haskell applications), you can use T.replace:
>>> replace "ofo" "bar" "ofofo"
"barfo"
Here's another possible solution using divide and conquer:
replaceO [] = []
replaceO (x:xs) =
if x == 'O'
then 'X' : replaceO xs
else x : replaceO xs
First, you set the edge condition "replaceO [] = []".
If the list is empty, there is nothing to replace, returning an empty list.
Next, we take the string and divide it into head and tail. in this case 'H':"ELLOWORLD"
If the head is equal to 'O', it will replace it with 'X'. and apply the replaceO function to the rest of the string.
If the head is not equal to 'O', then it will put the head back where it is and apply the replaceO function to the rest of the string.
replace :: Char -> Char -> String -> String
replace _ _ [] = []
replace a b (x : xs)
| x == a = [b] ++ replace a b xs
| otherwise = [x] ++ replace a b xs
I'm new to Haskell and I've tried to make it simpler for others like me.
I guess this could be useful.
main = print $ charRemap "Hello WOrld" ['O','o'] ['X','x']
charRemap :: [Char] -> [Char] -> [Char] -> [Char]
charRemap [] _ _ = []
charRemap (w:word) mapFrom mapTo =
if snd state
then mapTo !! fst state : charRemap word mapFrom mapTo
else w : charRemap word mapFrom mapTo
where
state = hasChar w mapFrom 0
hasChar :: Char -> [Char] -> Int -> (Int,Bool)
hasChar _ [] _ = (0,False)
hasChar c (x:xs) i | c == x = (i,True)
| otherwise = hasChar c xs (i+1)

Resources