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:

  1. 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
  2. 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!


Try using the functions from then ByteString package instead of System.IO and String as they are much more efficient. Also, consider using lazy IO (using heGetContents from the link I sent) to read the huge input file as it will not load it all at once in memory while you parse it making it more efficient.

  • \$\begingroup\$ oneway's code is already using lazy IO through the readFile function. \$\endgroup\$ – Changaco Sep 3 '13 at 10:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.