- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Re: Re: questioning FP
Ittay Dror <ittay.dror <at> gmail.com> writes:
> I'd love to see a code example where the introduction of IO[_] makes
> more errors detectable. In the code example I used in the first
> message, I couldn't find where it helps.
Simple:
foo : Int => Int
If your language is impure (like Scala), foo can format your HD, store and
retrieve stuff in a DB etc. If your language is pure, foo will always return the
same value given the same argument and it will do nothing else, thus it's much
easier to verify it's behavior.
You are thinking backwards, it's not the functions that perform side effects
that are easy to test, it's the ones that have no side effects. Problem in a
language without effects tracking is that you have no idea or control over which
functions perform side effects.
Also, knowing that a function is pure gives the compiler more options for
optimization, it can memoize the return value, it can complete remove calls if
the result is not used, it can parallelize calls etc.
So, how do you keep the language pure and still allow side effects? The IO monad
is a quite natural solution to that.
> If I have
> code that does 'for (_ <- close(socket); _ <- close(socket))',
> it will fail just the same as the (simpler) imperative code
> "socket.close; socket.close", wouldn't it? Side effects are not
> gone. They are just abstracted over, the question is whether the
> abstraction helps.
You have just discovered that ';' is shorthand for flatMap. It's the same
abstraction.
/Jesper Nordenberg










Fwd: Re: questioning FP
---------- Forwarded message ----------
From: Rex Kerr
Date: Sat, Oct 15, 2011 at 2:40 PM
Subject: Re: [scala-debate] Re: questioning FP
To: Sébastien Bocq
Cc: Scala Users
On Sat, Oct 15, 2011 at 2:02 PM, Sébastien Bocq
wrote:
>
> True, but is there a good practical use case for maintaining extremely large stacks that must be traversed one element at a time in one sweep?
>
> You can build ropes on top finger trees, which present a good trade-off between traversing and other manipulation functions. But this is another discussion.
>
> Could you give an example of the flat structures common for IO? I don't see what you mean.
Sometimes it doesn't matter whether it's a stack or queue or what, as
long as you have all the elements. And anyway, _either_ use case is
an argument for a list, you don't need both (i.e. either a stack, or
mostly traversals).
Flat structures for IO? Okay. From the Java API:
Class FileOutputStream
void write(byte[] b, int off, int len)
Writes len bytes from the specified byte array starting at
offset off to this file output stream.
byte[] b looks pretty flat to me.
Any time you have a text file (and you want to read it in quickly so
other processes can modify it) you end up with a flat pile of lines of
text (or bytes). Any time you spend unflattening and parsing it in
your IO thread is wasted time when IO rates are limiting. (On
machines with many cores, this is almost always.)
A HTTP get request gives you a flat string.
And so on.
--Rex
Re: Re: questioning FP
On Mon, Oct 10, 2011 at 11:16 AM, Patrik Andersson <pandersson [at] gmail [dot] com> wrote:
Yes, until you call unsafePerformIO
--
Viktor Klang
Akka Tech LeadTypesafe - Enterprise-Grade Scala from the Experts
Twitter: @viktorklang
Re: Re: questioning FP
On Mon, Oct 10, 2011 at 11:22 AM, √iktor Ҡlang <viktor [dot] klang [at] gmail [dot] com> wrote:
Re: questioning FP
Patrik Andersson gmail.com> writes:
> So you're not safe then. If calling foo is not optional then neither is having
your HD be reformatted. IO buys us nothing in this - admittedly dumb - example.
I don't understand your objection. It's the guaranteed lack of side effects
that buys us something. "Int => IO[Int]" is the same as
"Int => World => (Int, World)" so obviously it's still a pure function.
Compared to "Int => Int" though it's much harder to verify its behaviour.
/Jesper Nordenberg
Re: Re: questioning FP
Razvan Cojocaru wrote:
You mean the ST Monad? Isn't it for just local state threads? To allow for computations to tap into the performance benefits of mutable data?
+1
Because someone has to generate the applicative. Once you have 2 functions that takes normal arguments and produce an Applicative, that applicative needs to be a monad for the functions to compose. AFAIU, monads don't compose in that M[_] and N[_] cannot be composed to M[N[_]], which is why all side effects (reading a file, opening a socket, querying a DB) all use IO and not a more specific monad (like FileIO, SocketAction etc.), if they did, and you needed to use to such functions with different monads you'd need to compose them, but you would not be able to
Ittay
Re: Re: questioning FP
2011/10/15 Rex Kerr <ichoran [at] gmail [dot] com>
Ok. They don't need to be large.
Stored in blocks of 4KB. If you can, it is more efficient to process these blocks as they arrive (e.g. UNIX pipes) than reading megabytes of texts into memory before doing anything.
A ByteString [1] or a rope [2] would be better.
[1] Rewriting Haskell Strings
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.117.9065&rep=rep1&type=pdf
[2] "Ropes: an Alternative to Strings"
http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9450&rep=rep1&type=pdf
It is not because API's are build this way today that they can't be made better in the future. A problem today is that these structures are impractical to implement or use when all you have is first-order functions. Back on track!
--
Sébastien
Re: Re: questioning FP
On Monday, October 10, 2011 3:54:05 PM UTC-4, Ittay Dror wrote:
This is not true. It's entirely possible for you to have a more granular DSL for your IO actions than simply the opaque "IO". And they can be monads individually, and they can commute with each other easily. For example, look at the MonadIO type class from the Haskell libraries. It's specifically for this purpose, to allow "io-like" monads to commute.
Don't take it to mean more than it does when people say that "monads don't compose". What that really means is this: If M[_] is a monad, and N[_] is a monad, then M[N[_]] may not be a monad. But it often is, and it depends on what M and N are. The implementation of the M[N[_]] monad then depends on the nature of one or the other monad, either M or N.
Applicative functors, on the other hand, always compose. If M[_] is Applicative, and N[_] is Applicative, then M[N[_]] is Applicative too, in a completely mechanical way that in no way depends on what M and N are. Note that all monads are applicative functors, but not all applicative functors are monads. So you can say that all monads M and N compose to form an applicative functor M[N[_]].
What is the difference between applicative functors and monads then? It's very simple. If you have two "effectful" functions, f:A=>M[B], and g:B=>M[C], then if you compose them, the "effect" produced by g depends on the value returned by f. So M has to be a monad if you want to compose them. But if you have two "effectful" values a:M[A] and b:M[B], then you can compose them with a "pure" function p:(A,B)=>C to form a result of type M[C]. In that case you only need an applicative functor because there is no dependency between the effects.
Re: Re: questioning FP
On Tue, Oct 11, 2011 at 11:45, Runar Bjarnason wrote:
>
> Don't take it to mean more than it does when people say that "monads don't
> compose". What that really means is this: If M[_] is a monad, and N[_] is a
> monad, then M[N[_]] may not be a monad. But it often is, and it depends on
> what M and N are. The implementation of the M[N[_]] monad then depends on
> the nature of one or the other monad, either M or N.
>
> Applicative functors, on the other hand, always compose. If M[_] is
> Applicative, and N[_] is Applicative, then M[N[_]] is Applicative too, in a
> completely mechanical way that in no way depends on what M and N are. Note
> that all monads are applicative functors, but not all applicative functors
> are monads. So you can say that all monads M and N compose to form an
> applicative functor M[N[_]].
>
> What is the difference between applicative functors and monads then? It's
> very simple. If you have two "effectful" functions, f:A=>M[B], and
> g:B=>M[C], then if you compose them, the "effect" produced by g depends on
> the value returned by f. So M has to be a monad if you want to compose them.
> But if you have two "effectful" values a:M[A] and b:M[B], then you can
> compose them with a "pure" function p:(A,B)=>C to form a result of type
> M[C]. In that case you only need an applicative functor because there is no
> dependency between the effects.
Fantastic explanation. If this is the kind of explanation that book is
going to come with, then it's going to be one of the best book
acquisitions I ever made.
You should blog these three paragraphs, with, perhaps, *very* brief
examples. What make them so good is precisely their concision.
Re: Re: questioning FP
Thanks,Razvan
On 2011-10-10, at 3:54 PM, Ittay Dror <ittay [dot] dror [at] gmail [dot] com> wrote:
Re: Re: questioning FP
My reasoning then is that wrapping side-effecting code in IO or not does not buy protection against serious (side-effecting) bugs. How easy it is to locate such bugs is going to come down to the usual suspects such as: Did the person separate, for example, IO stuff into a single module which can be debugged? If not then it happens all over the place and the whole program runs within the IO monad.
On Mon, Oct 10, 2011 at 12:29 PM, Jesper Nordenberg <megagurka [at] yahoo [dot] com> wrote:
Re: questioning FP
> My reasoning then is that wrapping side-effecting code in IO or not does not
> buy protection against serious (side-effecting) bugs. How easy it is to
> locate such bugs is going to come down to the usual suspects such as: Did
> the person separate, for example, IO stuff into a single module which can be
> debugged? If not then it happens all over the place and the whole program
> runs within the IO monad.
The usual approach is to write as many parts of your program as pure
functions and as few functions as possible using IO. That turns out to
work quite well.