One of the amazing things about Clojure is the fact that source code complexity scales very slowly. That is, you can change things quite drastically with just a few key strokes... That is, the "source complexity" of a Clojure code base has a really low "big Oh" value. What the hell am I talking about ? Well, in this post, I'll walk you through a simple function which parses an entire DNA FASTA file into key/value pairs in just a few lines.
This will demonstrate just how easy it is to acutally DO SOMETHING USEFUL with Clojure.
BTW Thanks to Lee Hinmman and Shiva Mankala for cooking up this example. You can find more like it at
https://github.com/jayunit100/BioClojure
But first, lets look at the "intorductory" LISP examples which we normally see floating around out there :
Fibonacci sequence in LISP (who cares) ....
(defun fib (n)
"Simple recursive Fibonacci number function"
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
OR maybe, the factorial function (again , who cares, this can be done in one line of java, to ) ....
(defun factorial (N)
"Compute the factorial of N."
(if (= N 1)
1
(* N (factorial (- N 1)))))
etc etc etc....
Its actually quite nauseating, because most of us want EXCUSES to use languages like Clojure, OCAML, and Scala in the workplace. So here is a wonderful example of how and why you might want to build a bioinformatics application in clojure . This function (given a couple of other helpers, which are not particularly important) parses down a FASTA file of multiple DNA meta data / seqeunce pairs , into a list.
(defn read-fasta-file
"Read a FASTA file, transforming it into a map with :meta and :dna keys."
[filename]
(let [text (.trim (slurp filename))
entries (-> text (.replaceAll "\r" "") (.split "\n\n") seq)]
(map #(let [[m dna] (.split % "\n")]
{:meta (transform-entry m) :dna dna})
entries)))
SO HOW DOES IT WORK ???
1) Define a function, named read-fasta-fle, that takes in a single filepath as an argument. (note , this fasta is split by double lines.
2) "slurp" the contents of the file into a string.
3) Now, trim that string.
4) Bind the output of (3) to the variable "text".
5) (This one is tricky, skip it if you want to...) but ultimately, it binds "entries" to the "two line" records that we all know and love in FASTA files.
>name=CDK1 org=HomoSapiens taxid=9606 <---- line 1
ATCACAGCAATCAGCGCGTACAG <----- line 2
Thus "entries" is simply a list of Strings, where each string has 2 lines.
6) Now, declare an anonymous functoin which splits a String by lines, and binds the 1st and 2nd lines to , respectively, "m" and "dna" ; And then bind those to values to the a map which has exactly one 2 key s (m->line1 and dna->line2).
7) Finally, we're almost done. Just run that function for every line in the entries which we slurped up in (2).
The astute of you will notice an undefined function "transform-entry" in our midst. Thats for another day --- but briefly, its a function which maps the various meta data values in a fasta header into a map .
So the moral of the story is not clever. There is no punchline here. Its as simple as the following :
Parsing a FASTA file and doing something useful with it is something we've all had to do, usually in about 30 lines of try/catch riddled sphagetti, much uglier than the Cs101 java programs we all know and love. However, its just simple in Clojure as are the silly mathematical riddles that are typically touted as the sales pitch for Lisps /
That is --- the big Oh of source code complexity in clojure is really, really damn low.
This will demonstrate just how easy it is to acutally DO SOMETHING USEFUL with Clojure.
BTW Thanks to Lee Hinmman and Shiva Mankala for cooking up this example. You can find more like it at
https://github.com/jayunit100/BioClojure
But first, lets look at the "intorductory" LISP examples which we normally see floating around out there :
Fibonacci sequence in LISP (who cares) ....
(defun fib (n)
"Simple recursive Fibonacci number function"
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
OR maybe, the factorial function (again , who cares, this can be done in one line of java, to ) ....
(defun factorial (N)
"Compute the factorial of N."
(if (= N 1)
1
(* N (factorial (- N 1)))))
etc etc etc....
Its actually quite nauseating, because most of us want EXCUSES to use languages like Clojure, OCAML, and Scala in the workplace. So here is a wonderful example of how and why you might want to build a bioinformatics application in clojure . This function (given a couple of other helpers, which are not particularly important) parses down a FASTA file of multiple DNA meta data / seqeunce pairs , into a list.
(defn read-fasta-file
"Read a FASTA file, transforming it into a map with :meta and :dna keys."
[filename]
(let [text (.trim (slurp filename))
entries (-> text (.replaceAll "\r" "") (.split "\n\n") seq)]
(map #(let [[m dna] (.split % "\n")]
{:meta (transform-entry m) :dna dna})
entries)))
SO HOW DOES IT WORK ???
1) Define a function, named read-fasta-fle, that takes in a single filepath as an argument. (note , this fasta is split by double lines.
2) "slurp" the contents of the file into a string.
3) Now, trim that string.
4) Bind the output of (3) to the variable "text".
5) (This one is tricky, skip it if you want to...) but ultimately, it binds "entries" to the "two line" records that we all know and love in FASTA files.
>name=CDK1 org=HomoSapiens taxid=9606 <---- line 1
ATCACAGCAATCAGCGCGTACAG <----- line 2
Thus "entries" is simply a list of Strings, where each string has 2 lines.
6) Now, declare an anonymous functoin which splits a String by lines, and binds the 1st and 2nd lines to , respectively, "m" and "dna" ; And then bind those to values to the a map which has exactly one 2 key s (m->line1 and dna->line2).
7) Finally, we're almost done. Just run that function for every line in the entries which we slurped up in (2).
The astute of you will notice an undefined function "transform-entry" in our midst. Thats for another day --- but briefly, its a function which maps the various meta data values in a fasta header into a map .
So the moral of the story is not clever. There is no punchline here. Its as simple as the following :
Parsing a FASTA file and doing something useful with it is something we've all had to do, usually in about 30 lines of try/catch riddled sphagetti, much uglier than the Cs101 java programs we all know and love. However, its just simple in Clojure as are the silly mathematical riddles that are typically touted as the sales pitch for Lisps /
That is --- the big Oh of source code complexity in clojure is really, really damn low.




0 comments:
Post a Comment