Some background: I work mostly in Python (specifically numpy), doing Bioinformatics type work. I am interested in moving towards Haskell. Initially, I hope it will be possible to replace some of the simple exploratory scripting I've been doing with Haskell. The following is not something that would actually be particularly useful, but I thought it might be a good starting point for my first program in Haskell!
The following code takes two files:
- Describes regions of a chromosome that have been categorized as similar. Line 1 shows the start basepair of the region, line 2 the end basepair, and so on. A shortened example: http://pastebin.com/RMd13Kv3
- Shows an interaction matrix between "bins" of the chromosome. A row has chrmName startBp endBp, followed by the row of the interaction matrix. This is not necessarily in order. Example: http://pastebin.com/Q5CaVHAu
The code is attempting to work out the fraction of the whole chromosome spanned by the regions.
import System.IO
import System.Environment(getArgs)
import Data.Either
import Data.List
joinLinePairs :: [a] -> ([a], [a])
joinLinePairs x = partitionEithers $ zipWith ($) (cycle [Left, Right]) x
zipLinesPairs :: ([a], [a]) -> [(a, a)]
zipLinesPairs (a, b) = zip a b
pairDifference :: (String, String) -> Int
pairDifference (a, b) = (read b) - (read a)
domainArea :: [String] -> Int
domainArea inpLines = sum (map pairDifference $ zipLinesPairs $ joinLinePairs inpLines)
processRawMat :: [String] -> [[Int]]
processRawMat x = map (processMatRow . words) x
processMatRow :: [String] -> [Int]
processMatRow (x:y:z:_) = [read y, read z]
maxMinBin :: [[Int]] -> (Int, Int)
maxMinBin lst = (minimum vals, maximum vals)
where vals = concat lst
coverageFrac :: (Integral a, Fractional b) => (a, a) -> a -> b
coverageFrac (mn, mx) domArea = (fromIntegral domArea) / ((fromIntegral mx) - (fromIntegral mn))
main :: IO ()
main = do
args <- getArgs
rawDomains <- readFile (args !! 0)
let coveredArea = domainArea $ lines rawDomains
print $ coveredArea
rawMatrix <- readFile (args !! 1)
let rawMatLines = lines rawMatrix
let listolists = processRawMat rawMatLines
print $ coverageFrac (maxMinBin listolists) coveredArea
One thing I noticed is that this code is very slow when running on real data (in reality the second file can run to tens of thousands of lines, and hundreds of mb). As most of the things I would be doing involve dealing with very large text files (these would be considered small, by comparison), this worries me a bit!
I would appreciate any feedback anyone could offer me. Thanks!