Create a list of primes “as you go”, considering a number prime if it can’t be divided by any number already considered prime.
… However, although my straightforward solution worked on discrete ranges, it couldn’t yield a single prime when called on an infinite range — something I’m completely unused to from other languages, except for some experience with the SERIES library in Common Lisp.
… But when I suggested this on #haskell , someone pointed out that you can’t reverse an infinite list.
…This time when I put primes [1..] into GHCi it printed out prime numbers immediately, but visibly slowed as the accumulator grew larger.
I actually imported the full source into HackPorts, ripped out its List.hs file, renamed it to my Main.hs file, and then began changing it from a function that prints out a list of available packages, to one that writes the data into properly formatted Portfile entries.
… As it does this, it fetches the current version’s tarball over HTTP, and uses OpenSSL (directly, through FFI) to generate MD5, SHA1 and RIPEMD160 checksums of the tarball image.
…As a stub, I have them all depending on port:ghc , but I think there’s sufficient information in the Cabal package info to figure out what the right dependencies should be, both among the Hackage packages themselves and against any external libraries (like OpenSSL).
…Whereas map takes a list of values and returns a list of values, mapM takes a list of values and returns a list of actions that get invoked in sequence in the current Monad (in this case, IO ).
If it were a file I was checksumming, I could memory map the file and pass around a byte pointer, and the OS would take care of lazily reading in the bytes for me as needed.
…In C++ I’d have to switch from passing a vector to passing an istream iterator, but in Haskell, I don’t care what algorithm is populating my list, only that it is a list, and that I know how to work it.
…Based on the behavior of the program, I’m led to believe it happened near what the code was actually doing [^3] — but in fact the problem may have started long, long before, except that laziness differed the trigger to a later time.
… I still think the benefits can outweight the difficulties — especially when it comes to parallelism, and avoiding unnecessary computations, and allowing code to safely traverse infinite series — but it definitely requires a level of algorithmic conciousness on the part of the engineer which seems quite a bit higher than with imperative languages.
In the meantime, I’ve picked a toy project that also has a taste of usefulness: a script to convert the Hackage database into MacPorts Portfiles, respecting inter-package and external library dependencies.
…The impure part takes a command-line argument, interprets it as a FilePath (an impure type, since it must concern itself with operating system-dependent naming conventions), and reads the contents of the file at that location.
… This division into pure and impure has an interesting side-effect (no pun intended): Most of a program’s code is written in isolation of its context of usage .
… Too many times I’ve tried to use a utility’s code as a “library”, only to find it was so caught up in its idea of how it should be used, it had never bothered to abstract its core principles into a set of “pure” function, independent from that intent.
Recently I changed how the content on this site was generated, from using the standalone OS X application RapidWeaver , to the server-side publishing platform Movable Type . During that transition I changed the site’s style to the minimalist default offered by MT, which uses its own CSS for column layout and typography.
…I used the superb application CSSEdit to help me massage Movable Type’s style into something that compatible with Blueprint’s own typography and layout.
…I’m aware code examples were being truncated on the right side before, but this should be corrected now.
The task at hand is to write a wrapper script for /usr/bin/ld that drops arguments beginning with -Wl,-rpath, .
… Here ld-wrapper is expected to return its arguments separated by NUL characters so I can feed it to xargs , and from there to /usr/bin/ld . I’m sure there’s an easy, all-in-one way to do this with Haskell, I just haven’t reached that chapter yet.
… I wanted to do this with an “inverse grep” instead of select , but couldn’t find a way to grep for the opposite of a pattern.
It creates a Schroedinger type which has two data constructors: an Opened constructor which takes a Probable object — that is, whose Live or Dead state is known — and an Unopened constructor which takes a random generator, and an object without a particular state, such as a Cat.
… If, however, you bind a function to an Opened box with a Live thing, it will apply the function to what’s in the box — in this case, the Cat itself.
… Here is the meat of this example, it’s reason for being, all contained within this one line: If you bind a function to an Unopened box, it gets bound in turn to an Opened box containing a Cat whose fate has been decided by the dice.
… This is fairly linear: it gets a random generator from the operating system, then creates an Unopened box and returns it, which gets printed. print does its work by calling show on the Schroedinger type, since it was derived from Show earlier.
Having just begun my descent down the rabbit hole, into a Haskell land of hiding grins and late late hatters, I thought I’d try journaling what I discover on the way, so that maybe those who are merely curious could play the part of language voyeur.
… This function starts out the list with 1, followed by 1, then it starts adding two lists together — provided by the same function before it’s even done!
…I kept thinking it was something I had to return as I went along, not passed down to each deeper level — and then returned after I’d added to it.
…If that first character is a colon, return a list with the current accumulator as the head, and recurse to process the rest of the string (and so on).
In a recent entry on differences between Haskell and Lisp, one of the Lisp community’s long-time members, Daniel Weinreb, asked about my stated aversion to JVM-based languages for everyday computing (some times referred to as “scripting”).
… The fact that you distinguish between server-side and client-side applications suggests to me that what you’re really talking about is start-up latency: you’re saying that a very small program written for the JVM nevertheless has a significant fixed overhead that causes perceived latency to the user.
… As a hypothetical question just to clarify your meaning: if there were a JVM implementation that started up instantly, so that the speed of execution of a small program would be the same as the speed of the same code appearing in the middle of a long-running server process, would that answer your objections?
…Also, what you said about the JIT, and alternative VMs, can be supplemented by mentioning all the other JVM facilities that exist, like code coverage, performance and memory analysis, and live introspection; along with the ability to pick JVMs to run on phones, or satisfy real-time computing requirements.
Someone recently asked what my issue was regarding the JVM, since at the moment it prevents me from falling too much in love with Clojure — a language with the double-benefits of functional programming, and Lisp syntax and macros.
…These may not seem like much time in the scheme of things, but psychologically it builds up on me when I have to run a particular script over and over and over again. I’ve already noticed the pain with Groovy.
…Ruby (1.9.1-p0) | 0.0196997523308 |
