Monad Input/Output and Monad Transformers

View: New views
10 Messages — Rating Filter:   Alert me  

Monad Input/Output and Monad Transformers

by Maciej Piechotka :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

1. Learning haskell I discovered that I/O should be avoided nearly 'at
all costs'. The problem is that the IO monad is the only one which have
more interactive work flow. There is Reader/Writer monad but in fact
AFAIU first one is about the environment and second one is about
logging. Implementation of Writer can be defined in terms of handles but
it is rather limited (either non-full implementation which may be
confusing or need of caching the result for pass etc.).

I searched the hackage but I didn't find package with pure I/O. Such
package may look like:

class (Monad m, Monoid v) => MonadInput v m where
    -- | Gets an element from input (line of text [with \n], 4096 bytes,
    --   or something like that). mzero on end
    getChunk :: m v
class (Monad m, Monoid v) => MonadOutput v m where
    -- | Puts an element
    putChunk :: v -> m ()

In similar way filters (for example buffered input) can be defined:
class (MonadInput v m) => MonadBufferedInput m where
    -- | If not whole chunk has been consumed at once (for example only
    --   first 3 elements from list) rest can be returned. It will be
    --   returned as part of the input on next getChunk call.
    returnChunk :: v -> m ()
data (MonadInput v m, Monoid v) =>
     BufferedInputT v m a = BufferedInputT a v

Also pipes may be defined (as far as I understand but I'm not 100% sure)
which probably will simplify the writing of network tests:

-- | Evaluates the first argument. If the getChunk is called the
--   evaluation is passed to second argument until the putChunk is
--   called, which argument is returned in the first argument
callPipeT :: (Monad m, Monoid v) =>
             PipeInputT v m a -> PipeOutputT v m b -> m (a, b)

I've started some tests but I'd be grateful for comments (well -
probably I'm not the first who come to this idea so a) there is such
package or b) my level of Haskell does not allow me to see the
problems).

2. I find writing monad transformers annoying.
Additionally if package defines transformer A and another transformer B
they need to be connected 'by hand'.

I find a simple solution which probably is incorrect as it hasn't been
used:

instance (MonadState s n, Monad (m n), MonadTrans m) =>
         MonadState s (m n) where
        get = lift get
        put = lift . put

(requires FlexibleInstances MultiParamTypeClasses FlexibleContexts
UndecidableInstances - two last are not extensions used by mtl)

Regards

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Monad Input/Output and Monad Transformers

by Bulat Ziganshin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello Maciej,

Thursday, July 2, 2009, 3:31:59 PM, you wrote:

> class (Monad m, Monoid v) => MonadInput v m where
>     -- | Gets an element from input (line of text [with \n], 4096 bytes,
>     --   or something like that). mzero on end
>     getChunk :: m v
> class (Monad m, Monoid v) => MonadOutput v m where
>     -- | Puts an element
>     putChunk :: v -> m ()

how about interact function?

--
Best regards,
 Bulat                            mailto:Bulat.Ziganshin@...

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Monad Input/Output and Monad Transformers

by Maciej Piechotka :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, 2009-07-02 at 15:43 +0400, Bulat Ziganshin wrote:

> Hello Maciej,
>
> Thursday, July 2, 2009, 3:31:59 PM, you wrote:
>
> > class (Monad m, Monoid v) => MonadInput v m where
> >     -- | Gets an element from input (line of text [with \n], 4096 bytes,
> >     --   or something like that). mzero on end
> >     getChunk :: m v
> > class (Monad m, Monoid v) => MonadOutput v m where
> >     -- | Puts an element
> >     putChunk :: v -> m ()
>
> how about interact function?
>

Well. As far as I know there is no way of using it with network.
Additionally there is hard to put monadic code in it:

myFunc :: (MonadInput i, MonadOutput o) =>
          (String -> m a) -> MyMonad i o m [a]

If m == IO - which may be a case in normal code it requires
unsafePerformIO with all it's problems. In testing I can use pipes and
Identity simplifying the whole testing - allowing user to use it's own
monads.

The other problem is that the order sometimes matters. Consider:
main = interact (\x -> "What's your name?\n" ++ "Hello:\n" ++ x)

For human being it is annoying but sometimes it is for example against
RFC.

Regards

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Monad Input/Output and Monad Transformers

by Luke Palmer-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Jul 2, 2009 at 5:31 AM, Maciej Piechotka <uzytkownik2@...> wrote:
2. I find writing monad transformers annoying.
Additionally if package defines transformer A and another transformer B
they need to be connected 'by hand'.

You have not given any concrete problems or examples, so it's hard for me to comment.  But at first glance, I would conjecture that you are relying too heavily on monads and sequential thinking.

Consider what your code would look like without a single monad.  Obviously you cannot talk to the network without IO, but your program can still be modeled purely, and then toss in IO at the last second to tie it to the network.  This model may be difficult for you because it requires your brain to be rewired; feel free to mail this list with concrete modeling problems and we will help you out.

As for the pure model, throw away Reader, Writer, State -- everything, and just use pure functions.  Then add monads back in at small scopes when they clean things up.

I used to approach problems by designing a monad for my whole program, using an appropriate stack of transformers.  I suspect such an approach led to the claim that "monads are not appropriate for large software systems" in a popular paper a few months ago.  As I have gained more experience, I found that this is the wrong way to go about using them.  Now my primary use of monads is within the scope of a single function, to tie together the helper functions in the where clause.

Luke



I find a simple solution which probably is incorrect as it hasn't been
used:

instance (MonadState s n, Monad (m n), MonadTrans m) =>
        MonadState s (m n) where
       get = lift get
       put = lift . put

(requires FlexibleInstances MultiParamTypeClasses FlexibleContexts
UndecidableInstances - two last are not extensions used by mtl)

Regards

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Monad Input/Output and Monad Transformers

by Jason Dagit-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



On Thu, Jul 2, 2009 at 1:18 PM, Luke Palmer <lrpalmer@...> wrote:
 

I used to approach problems by designing a monad for my whole program, using an appropriate stack of transformers.  I suspect such an approach led to the claim that "monads are not appropriate for large software systems" in a popular paper a few months ago.

Link please!  I googled but I couldn't find it :(  I'd like to find out what you and the authors have learned about the inappropriateness of monads for large software systems.


Thanks,
Jason

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re[2]: Monad Input/Output and Monad Transformers

by Bulat Ziganshin-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello Luke,

Friday, July 3, 2009, 12:18:21 AM, you wrote:

> I used to approach problems by designing a monad for my whole
> program, using an appropriate stack of transformers.  I suspect such
> an approach led to the claim that "monads are not appropriate for
> large software systems" in a popular paper a few months ago.  As I
> have gained more experience, I found that this is the wrong way to
> go about using them. 

was it ghc authors paper? :)

--
Best regards,
 Bulat                            mailto:Bulat.Ziganshin@...

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Monad Input/Output and Monad Transformers

by Maciej Piechotka :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, 2009-07-02 at 14:18 -0600, Luke Palmer wrote:

> On Thu, Jul 2, 2009 at 5:31 AM, Maciej Piechotka
> <uzytkownik2@...> wrote:
>         2. I find writing monad transformers annoying.
>         Additionally if package defines transformer A and another
>         transformer B
>         they need to be connected 'by hand'.
>
> You have not given any concrete problems or examples, so it's hard for
> me to comment.  But at first glance, I would conjecture that you are
> relying too heavily on monads and sequential thinking.
>
> Consider what your code would look like without a single monad.
> Obviously you cannot talk to the network without IO, but your program
> can still be modeled purely, and then toss in IO at the last second to
> tie it to the network.  This model may be difficult for you because it
> requires your brain to be rewired; feel free to mail this list with
> concrete modeling problems and we will help you out.
>
> As for the pure model, throw away Reader, Writer, State -- everything,
> and just use pure functions.  Then add monads back in at small scopes
> when they clean things up.
>

AFAIU you comment the 2de point only. I look at this moment from
library, not program point of view.

So consider the library IOMonad which defined some MonadInput v m monad.
Then you have NNTP library which has NntpT m monad.

Each of them defines appropriate stack such as that NntpT (State s) is
instance of MonadState. But if there is NntpT MyInput, where MyInput
isinstance of MonadInput, is not MonadInput. To do it with current
approach the libraries would have to be interlinked.

Also it is quite boring to include for all monad
instance ... => ... where
    f1 = lift f1
    f2 = lift f2
    ...

> I used to approach problems by designing a monad for my whole program,
> using an appropriate stack of transformers.

I thought about others which might have want to use my monads in their
functions...

> I suspect such an approach led to the claim that "monads are not
> appropriate for large software systems" in a popular paper a few
> months ago.

I'd appreciate the link - google find nothing. I fall in love in Haskell
about a week or two ago and I fall in love just after I started learning
it ;)

> As I have gained more experience, I found that this is the wrong way
> to go about using them.  Now my primary use of monads is within the
> scope of a single function, to tie together the helper functions in
> the where clause.
>
> Luke
>

Regards

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Monad Input/Output and Monad Transformers

by Gwern Branwen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

On Thu, Jul 2, 2009 at 5:05 PM, Maciej Piechotka wrote:
> I'd appreciate the link - google find nothing. I fall in love in Haskell
> about a week or two ago and I fall in love just after I started learning
> it ;)

"Research programming languages like Haskell [22] and ML [20] didn't
seem to offer any near-term solution. Diatchki's work on fine-grain
representation in Haskell [25] is not yet main-stream, and had not yet
started when we began work on BitC. Support for state in Haskell
exists in the form of the I/O monad [23], but in our opinion the
monadic idiom does not scale well to large, complexly stateful
programs,1  and imposes constraints that are unnatural in the eyes of
systems programmers."

Oh, and not only do our monads not scale, they're slow to boot:

" Ultimately, the problem with Haskell and ML for our purposes is that
the brightest and most aggressive programmers in those languages,
using the most aggressive optimization techniques known to the
research community, remain unable to write systems codes that compete
reasonably with C or C++. The most successful attempt to date is
probably the FoxNet TCP/IP protocol stack, which incurred a 10x
increase in system load and a 40x penalty in accessing external memory
relative to a conventional (and less aggressively optimized) C
implemenation. [ 4 ,6  ]"

http://www.bitc-lang.org/docs/bitc/bitc-origins.html

- --
gwern
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEAREKAAYFAkpNJWoACgkQvpDo5Pfl1oLpeQCcDXUnfBaitwii3rhortVqO8Fr
SXIAnAiKY5EGg/ssZHOaooP1ag1xGIE4
=iugB
-----END PGP SIGNATURE-----
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Parent Message unknown Re: Monad Input/Output and Monad Transformers

by John Lato-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> From: Maciej Piechotka <uzytkownik2@...>
>
> 1. Learning haskell I discovered that I/O should be avoided nearly 'at
> all costs'. The problem is that the IO monad is the only one which have
> more interactive work flow. There is Reader/Writer monad but in fact
> AFAIU first one is about the environment and second one is about
> logging. Implementation of Writer can be defined in terms of handles but
> it is rather limited (either non-full implementation which may be
> confusing or need of caching the result for pass etc.).
>

I'm not sure what you mean when you say that IO is the only monad with
a "more interactive work flow".  Do you mean that it allows
interleaving of input and output?  If so, I would ask what you're
doing that makes this a concern.

If it's for efficiency, don't worry about it.  Haskell's laziness
means that the language will take care of this for you.  A good
example is the bzlib[1] package; the "compress" function has type
"ByteString -> ByteString" and automatically handles the chunking of
data for you.

If you need to partially process an input to determine how the rest of
the input should be handled, there are many parser libraries
(parsec[2], polyparse[3], etc.) that can either help with this
directly or perhaps give ideas as to how you can handle it.

You may also want to look at the iteratee[4] package.  It sounds like
it may accomplish what you're trying to do, although the interface is
very different from what you specify.

>
> 2. I find writing monad transformers annoying.
> Additionally if package defines transformer A and another transformer B
> they need to be connected 'by hand'.
>

If this becomes onerous, I think the usual solution is to define
custom lifting functions for the most commonly performed operations.
However, my feeling is that you're probably trying to put together a
monad stack to model what you're trying to do too soon, when you'd be
better served trying to develop data structures and core functions
that describe what you want to do.  Of course, without more
information this is just a guess.

John Lato

[1] http://hackage.haskell.org/package/bzlib
[2] http://legacy.cs.uu.nl/daan/parsec.html,
http://hackage.haskell.org/package/parsec
[3] http://www.cs.york.ac.uk/fp/polyparse/,
http://hackage.haskell.org/package/polyparse
[4] http://okmij.org/ftp/Haskell/Iteratee/,
http://hackage.haskell.org/package/iteratee
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Monad Input/Output and Monad Transformers

by Richard Kelsall :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Gwern Branwen wrote:
...

> " Ultimately, the problem with Haskell and ML for our purposes is that
> the brightest and most aggressive programmers in those languages,
> using the most aggressive optimization techniques known to the
> research community, remain unable to write systems codes that compete
> reasonably with C or C++. The most successful attempt to date is
> probably the FoxNet TCP/IP protocol stack, which incurred a 10x
> increase in system load and a 40x penalty in accessing external memory
> relative to a conventional (and less aggressively optimized) C
> implemenation. [ 4 ,6  ]"
>
> http://www.bitc-lang.org/docs/bitc/bitc-origins.html

Interesting paper.

Putting these remarks in context, in case anyone takes them as a current
critique of Haskell, they are apparently about ten years out-of-date and
apply to this SML program

http://www.cs.cmu.edu/~fox/foxnet.html

I wonder what would happen if the program was ported and benchmarked
in a recent version of GHC.


Richard.

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@...
http://www.haskell.org/mailman/listinfo/haskell-cafe