On Sun, Jan 31, 2010 at 10:05 PM, Steven D'Aprano <ste...@remove.this.cybersource.com.au> wrote: > On Sun, 31 Jan 2010 20:22:36 -0800, Paul Rubin wrote: >> Terry Reedy <tjre...@udel.edu> writes: >>> Three of you gave essentially identical answers, but I still do not see >>> how given something like >>> >>> def f(): return 1 >>> >>> I differentiate between 'function object at address xxx' and 'int 1' >>> objects. >> >> In the languages they are talking about, there is no such thing as a >> function with no args. A function is closer to a mathematical function, >> i.e. a mapping from one type to another, so every function has an arg. > > Suppose I have a function that queries a website http://guessmyname.com > for a list of popular names and returns the most popular name on the > list. Obviously this name will change from time to time, so I can't just > get it once and treat the result as a constant. > > In a non-functional language, I'd write it something like this: > > > def get_popular_name(): > URL = 'http://guessmyname.com' > data = fetch(URL) > names = parse(data) > name = choose(names, 1) > return name > > name = get_popular_name() # call the function with no argument > f = decorate(get_popular_name) # treat the function as a 1st class object > > > How would Haskell coders write it? <snip> > Is this where you say "Monads" and everyone's eyes glaze over?
Yeah, basically. Your function has side-effects (i.e. it does I/O over the network), and thus some extra hoops need to be jumped through to reconcile that with the functional purity of the language. Assuming my understanding of monads is somewhat correct: get_popular_name would have the type: IO () -> IO String i.e. it takes no "real" parameters but does I/O, and returns a String. "IO" is a generic type, thus IO () is like IO<void>, and IO String is IO<String> (using Java/C#-like generics syntax). Wrapping things in IOs (the "IO monad") is how the type system models that I/O side effects are involved. So, get_popular_name would end up taking one argument, IO (). Now where does the caller get an IO () ? Well, the toplevel (i.e. the main function) is allowed to do IO (otherwise, we couldn't write very interesting programs), and thus is provided with an IO by the environment (through some sort of magic). Using this, it passes an IO () to get_popular_name (or it gets passed down the call stack and eventually winds up at get_popular_name) and we get back an IO String. And through some further monad trickery, we make sure that lazy evaluation is effectively bypassed for the I/O and we are able to rip the String out of its IO container and pass it to pure functions. And using the dark magic of "do-notation", we write the parts involving IO in pseudo-imperative style (the "<-" operator Paul mentioned is part of that). And there you have it (I think/hope). Supposedly, in practice, you don't need to know the monad guts of how the I/O system works in order to use it, you just need to be able to write do-notation. Cheers, Chris -- I really should read the monad chapters of my copy of "Real World Haskell". http://blog.rebertia.com -- http://mail.python.org/mailman/listinfo/python-list