[HN Gopher] Monads Schmonads: Functional Input Without Tears (PYFL)
___________________________________________________________________
Monads Schmonads: Functional Input Without Tears (PYFL)
Author : herodotus
Score : 22 points
Date : 2021-05-22 17:20 UTC (1 days ago)
(HTM) web link (billwadge.wordpress.com)
(TXT) w3m dump (billwadge.wordpress.com)
| resoluteteeth wrote:
| If you really want your program's output to be a pure function of
| its input you can use the "interact" function in Haskell. I would
| recommend that the author try this and see the limitations, since
| it might help him start to understand why Haskell uses the IO
| monad.
| oisdk wrote:
| [The original paper which introduced Monads to
| Haskell](https://www.microsoft.com/en-us/research/wp-
| content/uploads/...) is a fantastic read, and extremely easy to
| understand. It explains clearly why monads are a good option, and
| what problem they're meant to solve in Haskell.
|
| In the article itself, the line:
|
| > As it happens the computation will need the value of b before
| that of a. If this is a problem, we can write the definition of
| root1 as
|
| Is actually quite interesting: the problem being described there
| is almost _identical_ to one of the problems that Haskell had
| with I /O, which motivated the introduction of monads.
| sfvisser wrote:
| Not entirely sure the author understands what problem monads
| solve and how it relates to his examples.
|
| If you just needs a fixed set of inputs without dependencies,
| conditionals, branching etc you indeed don't need monads.
| loa_in_ wrote:
| Haskell uses monads to encompass IO actions because IO is so much
| more than the stdout and stdin. The stderr, file operations,
| accessing raw memory, network connections and all sorts of global
| states are the domain of the IO monad.
| garethrowlands wrote:
| In the Haskell example in the article, the `do`, braces,
| semicolon and `return ()` are not necessary:
| main = do { putStrLn "Hello, World!" ; return () }
|
| The code should read like this instead (and I think the linter
| would suggest this): main = putStrLn "Hello,
| World"
| Blikkentrekker wrote:
| From how I understand this approach, these are effectful
| functions that have the size effect of printing on a prompt when
| first ran.
|
| While it is true that they yield the same result back to the
| program on each invocation, so would _OCaml_ invocation
| `Printf.printf "Hello, World!"`, it namely always returns `()`,
| but it is quite an effectful function, of course.
| aranchelk wrote:
| > Haskell uses the seriously complex machinery of monads to do
| I/O, supposedly without side effects (I don't accept this).
|
| The consensus of many highly intelligent people knowledgeable on
| the subject seems to be monads allow you to maintain a pure
| language while performing IO. This shouldn't make it an
| incontestable fact, but probably should make disagreement worth
| more than a throwaway line -- that is if you want to avoid
| looking like a crackpot.
| bade wrote:
| I've proposed an approach that is simple, equation oriented and
| trivial to implement. I think a substantive discussion off its
| merits is more useful than arguing about consensuses.The
| Haskell alternative is to write what are obviously commands in
| what looks like C and I don't see this as pure. Sometimes the
| emperor has no clothes.
| goto11 wrote:
| > monads allow you to maintain a pure language while performing
| IO
|
| I/O is by definition not pure, but the use of monads allow a
| strict separation between the pure and impure parts of the
| code. I guess you can say that monads allow you to have a
| guaranteed pure sublanguage.
| thewakalix wrote:
| I'd say it's more that IO is a sublanguage. The type (Int ->
| IO Int) seems more specialized than the type (Int -> Int),
| for example.
| aranchelk wrote:
| Agreed, and AFAIK if you're implementing IO, it's either in
| the runtime or you're doing FFI, so bizarrely (again AFAIK)
| all of those statements are accurate.
|
| Edit: sorry I glossed over the last bit regarding a sub-
| language. The point is the whole language is considered (at
| least by many of its proponents) pure: monads + runtime + FFI
| are the gymnastics that allow one to perform IO in a pure
| language.
| Blikkentrekker wrote:
| That's not a consensus at all.
|
| Many are of the position that the IO monad is purely a type
| theoretical hack that allows one to control the order of
| effectful functions in _Haskell_ that under the surface creates
| a vacuous data dependency that ensures the optimizer must
| sequence them in a particular order.
|
| There is no consensus as to what the IO monad "is"; only what
| it's specific semantics with regard to execution order is.
|
| But it serves it's purpose in that allows one to control the
| order of certain effects in another wise non strict language
| while semantically not necessarily relying on controlling the
| order of execution of function calls.
|
| On the type level, the effect of the function is separated from
| the calling of the function and it's effect need not
| necessarily take place conceptually when the function be
| called; under the hood, it simply ensures that the optimizer
| cannot move out of order the effectful kernel of the function
| by way of this vacuous data dependency.
| anderskaseorg wrote:
| It's easy to demonstrate that the IO monad is pure by
| reimplementing it in 100% pure code. {-#
| LANGUAGE GADTs #-} data IO' a where
| Pure :: a -> IO' a Bind :: IO' a -> (a -> IO' b) ->
| IO' b PutStrLn :: String -> IO' ()
| GetLine :: IO' String -- more IO operations...
| instance Functor IO' where fmap f ma = Bind ma
| (Pure . f) instance Applicative IO' where
| pure = Pure mf <*> ma = Bind mf (\f -> Bind ma
| (Pure . f)) instance Monad IO' where
| (>>=) = Bind
|
| The actual implementation in GHC is much more efficient, of
| course. GHC does all sorts of magic to hide the fact that
| it's generating straight-line code instead of a tree-like
| data structure full of continuation functions. But it's
| semantically equivalent.
| Twisol wrote:
| You're right, but I think there's a distinction here that
| is easy to miss.
|
| An IO action _describes_ what to do, but something still
| has to _do_ that action. A Haskell program on its own doesn
| 't do anything; that's exactly why it's pure. The Haskell
| runtime _interprets_ an IO value, unraveling it into the
| string of commands that comprise it. The runtime executes
| the commands produced by the Haskell program.
|
| Haskell uses monads exactly because it lets you
| describe/express complex sequences of actions (for which
| later actions depend on earlier actions) _without_
| requiring that the machinery for actually performing those
| actions be part of the program too.
| bitwize wrote:
| Monads don't make side effects in I/O go away, but they do help
| you manage them. Crucially, the IO monad _describes_ a
| computation which must then be _run_. Computations are
| describable in side-effect-free code. Running them is handled
| automatically by the Haskell runtime, and can be done without
| introducing side effects into the language.
| vmchale wrote:
| > Haskell uses the seriously complex machinery of monads to do
| I/O, supposedly without side effects (I don't accept this).
|
| Seems like the author doesn't understand what's going on.
| tromp wrote:
| > And you end up writing stuff like main = do { putStrLn
| "Hello, World!" ; return () } which to me looks like C. There
| must be a more functional approach.
|
| It looks imperative because that's what Haskell's do-notation
| was designed to. But it's merely syntactic sugar for the
| functional equivalent main = putStrLn "Hello,
| World!" >> return ()
|
| which btw is equivalent to simply main =
| putStrLn "Hello, World!"
___________________________________________________________________
(page generated 2021-05-23 23:01 UTC)