Python and Ruby

Chris Rebert clp2 at rebertia.com
Mon Feb 1 07:49:13 CET 2010


On Sun, Jan 31, 2010 at 10:05 PM, Steven D'Aprano
<steven at remove.this.cybersource.com.au> wrote:
> On Sun, 31 Jan 2010 20:22:36 -0800, Paul Rubin wrote:
>> Terry Reedy <tjreedy at 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



More information about the Python-list mailing list