Myths and debunking

December 9, 2011 | Filed Under Uncategorized | Leave a Comment 

Quoting Skeptical Science on debunking myths:

Common wisdom is that the more counter-arguments you provide, the more successful you’ll be in debunking a myth. It turns out that the opposite can be true. When it comes to refuting misinformation, less can be more. Debunks that offered three arguments, for example, are more successful in reducing the influence of misinformation, compared to debunks that offered twelve arguments which ended up reinforcing the myth.

For more information, read Schwarz, Sanna, Skurnik, Yoon: Metacognitive experiences and the intricacies of setting people straight: implications for debiasing and public information campaigns.

For commentary on how scientists should respond to denialists, read Diethelm and McKee: Denialism: what is it and how should scientists respond?

Another interesting paper: Reber and Schwarz: Effects of Perceptual Fluency on Judgments of Truth

See also:

http://rationalwiki.org/wiki/Denialism

Debunking Handbook Part 3: The Overkill Backfire Effect



Crabgrass Frontier vs Regurgitator’s Superstraight

October 7, 2011 | Filed Under Uncategorized | Leave a Comment 

If you could put a video clip to the book Crabgrass frontier: the suburbanization of the United States, it would have to be Regurgitator’s Superstraight:

Lyrics:

gimme love gimme good good times
here in suburbia the best you can buy
this is my home i keep my family inside
i’m late for work now honey i got to fly
he’s superstraight yeah he’s superstraight
i push my big sedan through the traffic jam
like salmon spawning to get into a can
i sing along to the pop radio
it’s propaganda but i know how it goes
you know i work all day and im out of my mind
i go man, im only human man i gotta unwind
i love my baby yeah shes number one
work girl means nothin i just bang her for fun
and when the weekend comes it’s time for my drugs
i suck em down count it two by one
help me remember to forget who i am
and when it’s over babe
that’s when it starts up again



Emacs + SLIME + SBCL setup

September 19, 2011 | Filed Under Uncategorized | Leave a Comment 

Recently I tried to set up Emacs, SLIME, and SBCL, all compiled from source. The instructions that I usually refer to say that you just need this in your .emacs to get SLIME working:

;; Set up the Common Lisp environment
(add-to-list 'load-path "/usr/share/common-lisp/source/slime/")
(setq inferior-lisp-program "/usr/bin/sbcl")
(require 'slime)
(slime-setup)

This doesn’t quite do it for the latest CVS version of SLIME. For example after typing “(defun ” nothing sensible showed up in the minibuffer at the bottom of the emacs window. By looking at the latest Ubuntu distribution’s slime init file, I found that this is also needed:


(eval-after-load "slime"
  '(progn
    (slime-setup '(slime-fancy slime-asdf slime-banner))
    (setq slime-complete-symbol*-fancy t)
    (setq slime-complete-symbol-function 'slime-fuzzy-complete-symbol)))

My full .emacs file is on GitHub: https://github.com/carlohamalainen/dotfiles/blob/master/.emacs.

Note: I only had to do this because I was compiling particular versions of SLIME and SBCL on a shared workstation. If you have a normal Ubuntu/Debian setup you can just apt-get install SLIME and everything will work as expected. I figure this bit of config might be useful for people working on other systems.



ggplot2 from Clojure

August 4, 2011 | Filed Under Uncategorized | Leave a Comment 

Just a quick note on how to call ggplot2 from Clojure. Install the rincanter package. A tip: if you don’t know what R_HOME is for your system, try this at the R prompt:

> R.home(component="home")
[1] "/usr/lib64/R"
>

So I did export R_HOME=/usr/lib64/R and then rincanter was happy.

When calling qplot, do not use r-eval because this tries to convert the entire plot into a Clojure object, resulting in unmanageable output. Use r-eval-raw instead.

I worked out the right commands by copying one of the answers to this stackoverflow question.



How to build a static Unison binary

July 29, 2011 | Filed Under Uncategorized | Leave a Comment 

The current documentation for Unison (as at 2.32.52) is slightly out of date, because the STATIC=true option to the Makefile does not do anything. The fix is to grab the patch file from this post and then apply it as follows:

cd unison-2.32.52
patch -p0 < ../patch-unison-static
make STATIC=true

Very handy if you have to run unison on a system with an old glibc.



Thinkpad X61 fan replacement

June 5, 2011 | Filed Under Uncategorized | 1 Comment 

The fan in my partner’s Thinkpad X61 started sounded crunchy so I decided to install a new one from IBM/Lenovo. For anyone considering this, I recommend this page on forum.thinkpads.com in particular the comment with datestamp Tue Apr 20, 2010 9:29 pm:

Things you don’t have to do that it [the Thinkpad service manual] says to do:

You don’t have to remove the ethernet or modem connectors in the upper right corner of the frame (or any screws there).

You don’t have to remove any modem cards, or cell cards, or any cards mounted on the motherboard (including the hard drive connector). Just move the wires out of the way.

With that bit of advice the job isn’t too tricky. You definitely need some good quality screwdrivers.

Here’s the X61 in pieces. The LCD is underneath the tea towel:

[photo]

It’s worth keeping track of the screws that you remove, in order:

[photo]

You have to take the whole thing apart because the screws that hold the fan assembly in place are on the bottom.

[photo]

The three main screws that hold on the fan assembly are quite tight, so I ended up using a vice-grip to loosen them:

[photo]



Asus EEE PC 1000H replacement fan

March 19, 2011 | Filed Under Uncategorized | 1 Comment 

I use an Asus EEE PC 1000H as a home file server. After being on 24/7 for a while the fan started getting noisy, so I ordered a replacement from 91deals on eBay. The fan was listed as “Asus Eee PC 1000 1000HA 1000HE CPU Fan BSB04505HA”.

Opening up the 1000H was a bit tricky due to some hidden clips, but this guide for the 1000HA had all the details.



SBCL stand alone + packages: copy ‘n’ paste instructions

March 5, 2011 | Filed Under Uncategorized | Leave a Comment 

Here are copy ‘n’ paste instructions for compiling and installing SBCL, and installing packages manually.
To compile SBCL we need an earlier SBCL binary; otherwise you may need to bootstrap using CLISP or CMUCL or some other Lisp variant. The SBCL installation guide has full details.

tar jxf sbcl-1.0.46-source.tar.bz2
cd sbcl-1.0.46
mkdir /opt/sbcl-1.0.46
sh make.sh --prefix=/opt/sbcl-1.0.46      # different if you don't have an earlier SBCL binary available
INSTALL_ROOT=/opt/sbcl-1.0.46 sh install.sh

Set the PATH and SBCL home directory in your ~/.bashrc:

export PATH=$PATH:/opt/sbcl-1.0.46/bin
export SBCL_HOME=/opt/sbcl-1.0.46/lib/sbcl

Install some custom packages in /opt/lisp. For example, the CFFI package requires babel, Alexandria, and trivial-features. Untar each package in /opt/lisp and then create (absolute) links to each package’s asd file:

cd /opt/lisp
ln -s /opt/lisp/alexandria/alexandria.asd .
ln -s /opt/lisp/babel_0.3.0/babel.asd .
ln -s /opt/lisp/cffi_0.10.6/cffi.asd .
ln -s /opt/lisp/trivial-features_0.6/trivial-features.asd .

Point SBCL to this package directory by adding these lines to ~/.sbclrc:

(require 'asdf)
(pushnew #P"/opt/lisp/" asdf:*central-registry* :test #'equal)
(push #P"/opt/lisp/" asdf:*central-registry*)

Now test that we can load the CFFI package:

carlo@foo:~> sbcl
This is SBCL 1.0.46, an implementation of ANSI Common Lisp.
More information about SBCL is available at .

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (asdf:operate 'asdf:load-op 'cffi)

; loading system definition from
; /opt/lisp/cffi.asd into #
; registering # as CFFI
; loading system definition from
; /opt/lisp/babel.asd into #
; registering # as BABEL
; loading system definition from
; /opt/lisp/alexandria.asd into
; #
; registering # as ALEXANDRIA
; loading system definition from
; /opt/lisp/trivial-features.asd into
; #
; registering # as TRIVIAL-FEATURES

(lots more output snipped)


Parsing with monads (can be) slow

February 11, 2011 | Filed Under Uncategorized | 5 Comments 

Update 2011-06-29: The title of this post should really be “Think about your grammer’s level of nondeterminism before writing an inflamatory blog post about monadic parsing.” I would like to thank the commenters for bringing various solutions to my attention. Also, someone seems to have posted it to reddit and there is a good conversation over there.

This post was written using BlogLiterately. The literate Haskell source file is parse_speed_test.lhs.

In late 2010 I went to a meeting of the Brisbane Functional Programmers Group. Tony Morris talked about using Haskell for parsing large GPS datasets. If I recall correctly, Tony said something like "you need to use arrows for parsing large datasets, not monads, because using monads will be slow."

Someone from the audience asked why this was the case, but no one was able to give a clear answer. I decided to write a small parser using monads in Haskell and collect some run times. In the code below, I borrowed a few definitions from some slides of an earlier talk by Tony Morris at BFPG, such as bindParser, mapParser, sequenceParser, etc. Tony’s slides are quite good so I won’t attempt to repeat his explanation of how monads can be used for parsing.

> import Data.Char
> import Maybe
> import System.Environment
>
> data Parser a = P {
>   parse :: String -> Maybe (String, a)
> }
>
> instance Monad Parser where
>   (>>=) = bindParser
>   return = value
>
> failed :: Parser a
> failed = P (\_ -> Nothing)
>
> character :: Parser Char
> character = P (\s -> case s of [] -> Nothing
>                                (c:r) -> Just (r, c))
>
> (|||) :: Parser a -> Parser a -> Parser a
> P p1 ||| P p2 = P (\s -> case p1 s of v@(Just _) -> v
>                                       Nothing -> p2 s)
>
> mapParser :: Parser a -> (a -> b) -> Parser b
> mapParser (P p) f = P (\s -> case p s of Just (r, c) -> Just (r, f c)
>                                          Nothing -> Nothing)
>
> bindParser :: Parser a -> (a -> Parser b) -> Parser b
> bindParser (P p) f = P (\s -> case p s of Just (r, c) -> parse (f c) r
>                                           Nothing -> Nothing)
>
> value :: a -> Parser a
> value a = P (\s -> Just (s, a))
>
> (>>>) :: Parser a -> Parser b -> Parser b
> p >>> q = bindParser p (\_ -> q)
>
> sequenceParser :: [Parser a] -> Parser [a]
> sequenceParser [] = value []
> sequenceParser (h:t) = bindParser h (\a -> mapParser (sequenceParser t) (\as -> a : as))
>
> list :: Parser a -> Parser [a]
> list k = many1 k ||| value []
>
> many1 :: Parser a -> Parser [a]
> many1 k = bindParser k (\k' -> mapParser (list k) (\kk' -> k' : kk'))
>
> satisfy :: (Char -> Bool) -> Parser Char
> satisfy p = bindParser character (\c -> if p c then value c else failed)
>
> is :: Char -> Parser Char
> is c = satisfy (== c)
>
> space :: Parser Char
> space = satisfy isSpace
>
> alpha :: Parser Char
> alpha = satisfy isAlpha

Let’s try to parse an XML-like document. For simplicity we will use angle brackets (as in normal XML) and allow any other character in a tag’s name:

> nonAngleBracket c = not $ c `elem` ['<', '>']
>
> xmlTagNameParser :: Parser String
> xmlTagNameParser = many1 (satisfy nonAngleBracket)

An open tag has a left angle bracket, some characters for the name, and a right angle bracket. This can be written very succintly in Haskell with do notation:

> openTagParser :: Parser String
> openTagParser = do list space
>                    is '<'
>                    tag_name <- xmlTagNameParser
>                    is '>'
>                    return (head (words tag_name))

Similarly for a closing tag:

> closeTagParser :: Parser String
> closeTagParser = do list space
>                     is '<'
>                     is '/'
>                     tag_name <- xmlTagNameParser
>                     is '>'
>                     return tag_name

The text inside a basic XML structure can be any ASCII character except for an opening bracket.

> xmlTextFieldParser :: Parser String
> xmlTextFieldParser = list (satisfy (\c -> isAscii c && (c /= '<')))

The simplest XML structure that we will parse is a balanced pair of tags with some text inbetween, such as: <foo>hey there</foo>.

> xmlTextElementParser :: Parser [(String, String)]
> xmlTextElementParser = do open_tag_name   <- openTagParser
>                           text_body       <- xmlTextFieldParser
>                           close_tag_name  <- closeTagParser
>                           if open_tag_name /= close_tag_name then failed else return [(close_tag_name, text_body)]

The other kind of structure that we can parse is a pair of balanced tags with some list of text bits inside, such as:

<foo><bar>bar value</bar><meh>meh value</meh></foo>

The top level definition of the parse is thus:

> xmlToTagValueList :: Parser [(String, String)]
> xmlToTagValueList =
>   do open_tag_name    <- openTagParser
>      body             <- many1 (xmlTextElementParser ||| xmlToTagValueList)
>      close_tag_name   <- closeTagParser
>      if open_tag_name /= close_tag_name then failed else return ((close_tag_name, "->"):(concat body))

For testing purposes we will try to parse the input file and then report the number of parsed XML-like elements.

> main = do args <- getArgs
>           x <- readFile (head args) :: IO String
>           let x' = parse (list xmlToTagValueList) x
>           print (length (head (snd (fromJust x'))))

For testing I will use a file with one line repeated inside a <blah> block. The file input10.txt has 10 lines in the inner block:

 <blah>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
     <hello> do de dah</hello> <foo> <bar>bar</bar> </foo>
 </blah>
 

Here are some run times on a lightly loaded 2Ghz Xeon running Ubuntu 10.10 with GHC 6.12.1, and the binary compiled with "ghc -O –make". This parse is clearly impractical if parsing 30 lines of text will take over 1.5 hours:

Nr lines time (seconds)
1 0.116
10 0.015
15 0.468
20 16.166
25 466.365
30 > 5000

This kind of issue turns out to be a well known problem with monadic parsing. The answer comes from John Hugh’s 1998 paper Generalising Monads to Arrows, from which I now quote:

Although the idea of programming with combinators is quite old, the design of combinator libraries has been profoundly infuenced in recent years by Wadler’s introduction of the concept of a monad into functional programming[Wad90, Wad92, Wad95]. We shall discuss monads much more fully in the next section, but for now, suffice it to say that a monad is a kind of standardised interface to an abstract data type of `program fragments’. The monad interface has been found to be suitable for many combinator libraries, and is now extensively used. Numerous benefits flow from using a common interface: to take just one example, Haskell has been extended with special constructions to make the use of monads particularly convenient.

It is therefore a matter for some concern when libraries emerge which cannot, for fundamental reasons, use the monad interface. In particular, Swierstra and Duponcheel have developed a very interesting library for parsing LL-1 grammars[SD96], that avoids a well-known inefficiency in monadic parsing libraries by combining the construction of a parser with a `static analysis’ of the program so constructed. Yet Swierstra and Duponcheel’s optimisation is incompatible with the monad interface. We believe that their library is not just an isolated example, but demonstrates a generally useful paradigm for combinator design that falls outside the world of monads. We shall look more closely at their idea in section 3. Inspired by Swierstra and Duponcheel’s library, I sought a generalisation of the monad concept that could also offer a standardised interface to libraries ofthis new type. My proposal, which I call arrows, is the subject of this paper. Pleasingly, the arrow interface turned out to be applicable to other kinds of non-monadic library also, for example the fudgets library for graphical user interfaces [CH93], and a new library for programming active web pages. These applications will be described in sections 6 and 9.

While arrows are a little less convenient to use than monads, they have significantly wider applicability. They can therefore be used to bring the benefits of monad-like programming to a much wider class of applications.

The paper by Swierstra and Duponcheel pretty much sums things up:

As soon as one starts to use normal combinator based parsers, disappointments arise. The parsers constructed may be unexpectedly slow, and since combinators are usually used to describe non-deterministic parsers, they do not perform any form of error-reporting, let alone error-recovery. Even the smallest mistake in the input may lead to a lengthy parsing process which finally produces an empty list of successful parses, with no clue as to where where the mistake is located.

To learn about arrows in Haskell, go here: http://www.haskell.org/arrows/.



Monad motivation

February 11, 2011 | Filed Under Uncategorized | Leave a Comment 

This blog post was written using BlogLiterately. The literate Haskell source file is monad_motivation.lhs.

Introduction

Most languages have a value like the C language’s NULL which can be used to represent "no value" or "invalid value." Because NULL has type int in the C language, the following program happens to be valid:

 #include 

 int main()
 {
     int *x = NULL;
     x++;

     return 0;
 }
 

Obviously it’s silly to increment NULL by one, but it’s fine in C because NULL is just an integer. Haskell offers us a type system that lets us make explicit the idea that we either have a value, or we have no value at all. The Maybe data type is defined in the standard prelude as:

> data Maybe a = Just a | Nothing

Monads for sheep

To see how to use the Maybe type, we’ll follow an example from [1]. We have a partial family tree for some sheep, who are represented as integers. Using the father or mother functions we can work out a sheep’s maternal grandfather, or a sheep’s mother’s paternal grandfather, etc. Since we don’t have complete information about every sheep’s lineage, we return the type Maybe Sheep instead of Sheep.

> type Sheep = Integer
>
> father :: Sheep -> Maybe Sheep
> father 0 = Just 1
> father 1 = Just 3
> father 2 = Just 5
> father 5 = Just 7
> father _ = Nothing
>
> mother :: Sheep -> Maybe Sheep
> mother 0 = Just 2
> mother 1 = Just 4
> mother 5 = Just 6
> mother _ = Nothing
>
> maternalGrandfather :: Sheep -> Maybe Sheep
> maternalGrandfather s = case (mother s) of
>     Nothing -> Nothing
>     Just m  -> father m
>
> mothersPaternalGrandfather :: Sheep -> Maybe Sheep
> mothersPaternalGrandfather s = case (mother s) of
>     Nothing -> Nothing
>     Just m  -> case (father m) of
>         Nothing -> Nothing
>         Just gf -> father gf

Handling the Just and Nothing cases becomes tedious as can be seen in the definition of mothersPaternalGrandfather. Perhaps an improvement would be to modify the functions mother and father so that they accept a Maybe Sheep as input:

> father' :: Maybe Sheep -> Maybe Sheep
> father' (Just 0) = Just 1
> father' (Just 1) = Just 3
> father' (Just 2) = Just 5
> father' (Just 5) = Just 7
> father' _ = Nothing
>
> mother' :: Maybe Sheep -> Maybe Sheep
> mother' (Just 0) = Just 2
> mother' (Just 1) = Just 4
> mother' (Just 5) = Just 6
> mother' _ = Nothing
>
> maternalGrandfather' :: Sheep -> Maybe Sheep
> maternalGrandfather' s = father' (mother' (Just s))
>
> mothersPaternalGrandfather' :: Sheep -> Maybe Sheep
> mothersPaternalGrandfather' s = father' . father' $ mother' (Just s)

This is an improvement since we can write maternalGrandfather' and mothersPaternalGrandfather' using a single line for each. However, this comes at the cost of making father' and mother' take a Maybe Sheep type as input, and it requires the redundant f Nothing = Nothing line in each. Why would we call the father' function if we didn’t have a real sheep identifier as input?

So let’s try to keep the original father and mother definitions, with type signatures

> father :: Sheep -> Maybe Sheep
> mother :: Sheep -> Maybe Sheep

What we want is some equivalent way of combining a sequence of calls to father or mother, with the result that the Nothing value is propagated along. We can do this with a combinator:

> comb :: Maybe a -> (a -> Maybe b) -> Maybe b
> comb Nothing  _ = Nothing
> comb (Just x) f = f x

If we try to combine Nothing with any function we get Nothing back. Otherwise we unwrap the value from the Maybe type and apply the given function. Now mothersPaternalGrandfather can be rewritten in a much nicer form:

> mothersPaternalGrandfather2 :: Sheep -> Maybe Sheep
> mothersPaternalGrandfather2 s = (Just s) `comb` mother `comb` father `comb` father

Combinators for lists

The sheep combinator seems like a good idea, so it is natural to ask if we can use it for any other problems. Perhaps there is an analagous combinator for lists? To find out, let’s make a Lisp-style list data type (here we follow the example in [2]). A list is either an item followed by another list, or just an empty list. For example the list [1, 2, 3] would be written as

> Item 1 (Item 2 (Item 3 End))

Let’s define the List data type and a few handy functions:

> -- Lisp-style list constructor
> data List a = Item a (List a) | End
>     deriving (Show)
>
> -- Send a value into a list
> inject :: a -> List a
> inject a = Item a End
>
> -- Add two lists together. Example:
> -- listAdd (Item 1 (Item 2 (Item 3 End))) (Item 4 (Item 5 End)) = Item 1 (Item 2 (Item 3 (Item 4 (Item 5 End))))
> listAdd :: List a -> List a -> List a
> listAdd End End = End
> listAdd (Item x xs) y = Item x (listAdd xs y)
> listAdd End (Item y ys) = Item y (listAdd End ys)
>
> -- Concatenate a list of lists. For example:
> -- listConcat (Item (Item 1 (Item 2 (Item 3 End))) End) = Item 1 (Item 2 (Item 3 End))
> listConcat :: List (List a) -> List a
> listConcat End = End
> listConcat (Item x xs) = listAdd x (listConcat xs)
>
> -- Apply a function f to each element of a list.
> -- Example: listMap (\x -> x + 1) (Item 1 (Item 2 (Item 3 End))) = Item 2 (Item 3 (Item 4 End))
> listMap :: (a -> b) -> List a -> List b
> listMap f End = End
> listMap f (Item x xs) = Item (f x) (listMap f xs)

The sheep combinator had type signature

> Maybe a -> (a -> Maybe b) -> Maybe b

so let’s assume that the list combinator has the same type except that Maybe is replaced with List:

> List a -> (a -> List b) -> List b

We aren’t sure how this combinator should be defined, so let’s start by supposing that we have the inputs f :: a -> List a and x :: List a. It seems sensible to apply f to each element of x. We can do this with the function listMap that we defined earlier. The expression listMap f x has type List (List b). To transform List (List b) into List b we can use listConcat. This reasoning, purely about types, in fact leads us to the correct definition of the list combinator:

> listComb :: List a -> (a -> List b) -> List b
> listComb End _ = End
> listComb list f = listConcat (listMap f list)

Having defined the list combinator, let’s see how it could be used in the simple situation of filtering out elements of a list. A normal list filter would be written as follows:

> listFilter :: (a -> Bool) -> List a -> List a
> listFilter _ End = End
> listFilter f (Item x xs) = if f x then Item x (listFilter f xs) else listFilter f xs

We can use listFilter to select only the strictly positive elements of a list:

Prelude> :type (> 0)
(> 0) :: (Num a, Ord a) => a -> Bool
Prelude> (> 0) 1
True
Prelude> (> 0) (-10)
False
*Main> listFilter (> 0) (Item 1 (Item 2 (Item (-1) End )))
Item 1 (Item 2 End)

In terms of listComb, the input list would be the list itself. The function must take each element of the input list to a new list based on some criteria. So given an element x and function p, the natural definition would be

> x -> if p x then [x] else []

Using our List data type the definition is just:

> myfilter :: (a -> Bool) -> List a -> List a
> myfilter p list =
>     list `listComb` (\x -> if p x then inject x else End)

Here is an example where we select the strictly positive elements of a list:

*Main> myfilter (> 0) (Item 1 (Item 2 (Item (-1) End )))
Item 1 (Item 2 End)

Monads in Haskell

Haskell provides a way to invoke the combinator for a certain type without having to specify its name explicitly each time. What we can do is define List to be an instance of Monad in Haskell’s type system and then use the do notation to invoke the combinator. This gives an eerily procedural-looking definition of myfilter:

> instance Monad List where
>     return x = inject x
>     list >>= f = listComb list f
>
> myfilter' :: (a -> Bool) -> List a -> List a
> myfilter' p list = do
>     x <- list
>     if p x then inject x else End

The function myfilter' behaves in exactly the same way as myfilter:

*Main> myfilter' (> 0) (Item 1 (Item 2 (Item (-1) End )))
Item 1 (Item 2 End)

[As an aside, I think that the do notation is unfortunate. The English language word "do" implies an action, possibly followed by another action, but this is not what happens with the list combinator. Even worse, to a programmer used to procedural languages, the <- looks like assignment, but in this (incorrect) imperative reading of myfilter', the type of x will be inconsistent (either List a or a). On the other hand, a completely new syntax would probably make people complain that the concept at hand is too alien to even bother with, in the same way that people still find Lisp's parentheses to be offputting.]

Simon Dobson wrote a blog post [3] explaining another viewpoint of Monads in Haskell: they are like a programmable semicolon. In pseudo-C, the myfilter' Monadic function might look like this:

myfilter'(p list)
{
    x <- list ;
    if p x then inject x else End
}

It is as if we we have defined the behaviour of ';' in this particular situation to take a list, and then combine it with the function on the next line using listComb. This is quite a powerful construct.

References

[1] http://www.haskell.org/all_about_monads/html/meet.html
[2] http://ianen.org/articles/monad-is-not-difficult/
[3] http://www.simondobson.org/2010/06/monads-language-design-perspective/
[4] http://www.randomhacks.net/articles/2007/03/12/monads-in-15-minutes



Next Page →