News for hackers. Stuff that matters.
Re:Why functional programming matters (1990) [pdf] by mafribe on Thursday May 07, 2015 @12:08PM (#9506084)
Thanks for your question. Consider this stateful program in pseudo-code

    def f x = 
       let i = ref 17 in
       while i > 0 { i := i-1 }
       return i 
It is referentially transparent. The literal translation into Haskell needs the state monad, despite referential transparency.
Re:Why functional programming matters (1990) [pdf] by tel on Thursday May 07, 2015 @01:34PM (#9506801)
This is a regionalized or "benign" effect. To the degree that this can be proven in Haskell's synthetic effect calculus it's OK. Since Haskell does have `unsafePerformIO` we can, with great care, introduce new rules to the type system. This is how `ST` was created

    -- we need a primitive first
    while :: Monad m => m Bool -> m a -> m ()
    while conde bodye = do
      cond <- conde
      if cond then bodye else return ()

    -- then we can make a direct, verified pure translation
    f :: a -> Int
    f x = runST $ do
      i <- newSTRef 17
      while (readSTRef i >>= \ival -> return (ival > 0)) $ do
        modifySTRef i (\ival -> ival - 1)
      ival <- readSTRef i
      return ival
Re:Why functional programming matters (1990) [pdf] by dllthomas on Thursday May 07, 2015 @04:20PM (#9507982)
I think your "while" is "when".
Re:Why functional programming matters (1990) [pdf] by tel on Thursday May 07, 2015 @05:54PM (#9508590)
Oh, thanks! Good catch. Here's `while`

    while :: Monad m => m Bool -> m a -> m ()
    while conde bodye = do
      cond <- conde
      if cond then bodye >> while conde bodye else return ()
Re:Why functional programming matters (1990) [pdf] by dllthomas on Thursday May 07, 2015 @02:27PM (#9507172)
There are several candidate translations. Which you might choose depends on those constraints on the actual problem (instead of this pretend one) that make "f x = 0" not an eminently better solution.

The one that probably most closely matches the semantics of the pseudo-code would be:

    let f0 x = unsafePerformIO $ do
        iRef <- newIORef 17
        whileM_ (fmap (>0) $ readIORef iRef) $ do
            modifyIORef iRef (\ i -> i - 1)

        readIORef iRef
Better would be to let Haskell help check that the mutation is local and no references escape:

    let f1 x = runST $ do
        iRef <- newSTRef 17
        whileM_ (fmap (>0) $ readSTRef iRef) $ do
            modifySTRef iRef (\ i -> i - 1)

        readSTRef iRef
There's the more idiomatic translation, where for something this simple we wouldn't bother with State:

    let f2 x = go 17
      where
        go i | i > 0 = go (i - 1)
             | otherwise = i

The literal translation using State is:

    let f3 x = execState countdown 17
      where
        countdown = whileM_ (>0) $ modify (\ i -> i - 1)
In all cases, the function as a whole is referentially transparent.

In your function, "while i > 0 { i := i - 1 }" is clearly not referentially transparent. Attempting to transliterate in a way that preserves this expression, it is unsurprising that we wind up with expressions that depend on state. The State monad is one way of encapsulating this. Note that f3 and f2 are actually very similar. The execState function doesn't do any deep voodoo - a value of type "State s a" is a thin wrapper around a function of type "s -> (a, s)"; execState simply extracts this function, applies it to a value, and returns the second part of the output.

The actual definitions are equivalent to these (albeit slightly more complicated to keep things DRY w/ transformers):

    newtype State s a = State (s -> (a, s))

    execState (State f) s = let (_, s') = f s in s'

What I don't see, in any of this, is a problem (conceptual or practical) involving "destructors". Is your objection to the need to call execState (or its friends)?
Re:Why functional programming matters (1990) [pdf] by mafribe on Thursday May 07, 2015 @09:44PM (#9509559)
Thanks. Do any of these renditions have the target type int -> int?
Re:Why functional programming matters (1990) [pdf] by dllthomas on Friday May 08, 2015 @02:34AM (#9510273)
All of them.

More precisely, since the argument isn't used it's type is unconstrained, and the result could be any numeric type, so they all actually have type (Num b => a -> b), but that can be used anywhere you're expecting an Int -> Int.

Re:Why functional programming matters (1990) [pdf] by dragonwriter on Thursday May 07, 2015 @12:52PM (#9506457)
> The literal translation into Haskell needs the state monad, despite referential transparency.

Sure, literally translating imperative procedures into Haskell code often needs the State monad since imperative procedures gratuitously use state modifications that are logically unnecessary for their function.

But I'm not sure why any meaning should be ascribed to this beyond "translate function, not code".

Re:Why functional programming matters (1990) [pdf] by tome on Thursday May 07, 2015 @12:40PM (#9506360)
Could you be more precise? The obvious way to translate this into Haskell is 'f x = 0'.
Re:Why functional programming matters (1990) [pdf] by mafribe on Thursday May 07, 2015 @11:21PM (#9509810)
While f x = 0 is extensionally equal to the original program, it doesn't implement the algorithm in question (iteratively counting down a local reference).
Re:Why functional programming matters (1990) [pdf] by tome on Friday May 08, 2015 @02:00AM (#9510191)
Ok, so how about

    f x = g 17 x
        where g i x = if i > 0 then g (i - 1) x else i
Re:Why functional programming matters (1990) [pdf] by mafribe on Friday May 08, 2015 @02:26AM (#9510249)
The point of the example was to (1) use mutable state (hence force the state monad to show up in the function's type), but (2) in a way that defines a pure function.

The example is intended to point towards an expressivity gap of the monadic encapsulation approach to effects, in that one can't (as far as I'm aware -- I have not programmed in Haskell) hide state usage, even when this is extensionally OK.

It is an open research question to define type/effect systems that (a) enable programmers to hide such benign state usage, (b) preserve type inference for interesting typing systems (say F-omega which is the heart of Haskell's types), and (c) are pragmatically viable.

Re:Why functional programming matters (1990) [pdf] by dllthomas on Friday May 08, 2015 @02:39AM (#9510290)
"The example is intended to point towards an expressivity gap of the monadic encapsulation approach to effects, in that one can't (as far as I'm aware -- I have not programmed in Haskell) hide state usage, even when this is extensionally OK."

You absolutely can do exactly that. Even without cheating (unsafePerformIO and friends), usually.

Re:Why functional programming matters (1990) [pdf] by mafribe on Friday May 08, 2015 @02:59AM (#9510342)
If this is always possible without cheating, then I have definitely misunderstood something about Haskell.

Could you point me towards an explanation how the hiding of stateful expressions works in Haskell in general?

Let me clarify my question (a bit). Are you saying one of the following is true?

(1) You are saying for any program M that uses state (i.e. M's type mentions the state monad in an essential way) but in a pure way, i.e. M's stateful behaviour is not visible from the outside, there is a context C[.] (not involving tricks like UnsafeIO) such that C[M] has the same behaviour as M (as seen from the outside), and C[M] has (essentially) the same type as M, except that the state monad is gone?

(2) There is a 'nice' translation function f on programs such that for any program M that uses state in a pure way (same as (1)), f(M) has the same behaviour as M (as seen from the outside), and f(M) has (essentially) the same type as M, except that the state monad is gone?

Re:Why functional programming matters (1990) [pdf] by dllthomas on Friday May 08, 2015 @10:17AM (#9511832)
I'm not sure I understand the distinction (quite possibly just 'cause it's early).

A fruitful way to look at monads is to say a value of type M (where M is an instance of Monad) is a program in a language. State is a language for describing stateful computation. Reader is a language for describing parameterized computation. ST is a language for describing controlled, local mutation. IO is a language for describing arbitrary side effects.

Most of these have pure interpreters, with the most generic typically called runM (so, runState, runReader, &c). The only place cheating comes in is unsafePerformIO - interpreting IO is the job of the runtime, which does it in a more controlled way relative to the rest of your program.

The type of the return value of an interpreter, of course, doesn't tell you what kind of program you ran - it just tells you the result.

Re:Why functional programming matters (1990) [pdf] by dllthomas on Friday May 08, 2015 @11:15AM (#9512129)
Revisiting to speak directly to the question you've asked, both 1 and 2 are true for the State monad.

For 1, to get from a value of type "State s a" to a value of type a, you simply call evalState and supply an initial state of type s.

For 2, you could look at the structure of the program and unwrap all (State s a) values to have type (s -> (a, s)), updating the various functions used to operate on (State s a) values to match.

In either case, you would not see State in the resulting type signature. In case 2, you would still need to provide an initial value of type s - you can't do much interesting with a function but apply it.

Note that the function in 2 is more theoretical than practical. You could in principle write it with Template Haskell, but since it doesn't change the behavior and you can just do 1 to change the type the same way there isn't reason to.

Re:Why functional programming matters (1990) [pdf] by mafribe on Monday May 11, 2015 @01:34AM (#9522886)
Thanks. This is very interesting, but different from what I used to believe about Haskell (as you can imagine, I'm not an active Haskell programmer). I will have to revisit my ideas.

I still wonder how this would work with scope extrusion of references. Consider this little Ocaml program

    let ( impure, pure ) =
      let i = ref 0 in
      let impure x = ( i := !i + 1; x + !i ) in
      let pure x = (
        i := !i + 1;
        let res = !i + x in
        i := !i - 1;
        res - !i ) in
      ( impure, pure );;
which returns two functions called "pure" and "impure". Both are of type int -> int. The function "pure" is computing the successor function (let's ignore corner cases), but using hidden state. The function "impure" is using the same hidden state, but is clearly impure.

Is it possible to do the same in Haskell? By "the same" I mean giving "pure" the type int -> int, despite using hidden state that is used elsewhere?

Re:Why functional programming matters (1990) [pdf] by dllthomas on Tuesday May 12, 2015 @08:26AM (#9531192)
It's harder to be confident about impossibility than about possibility, but I think this would require "cheating". I'm not sure if you meant it as a bug, but note that outside of a single-threaded context "pure" isn't referentially transparent - there seems to be a race condition that could lead to pure computing different values if impure is called during pure's execution.

Something with a similar form that would be more realistic to ask for would be a cache for a pure-but-expensive function and some IO operations to inspect/manipulate that cache. I believe you would need a call to unsafePerformIO, but that could be a reasonable thing to do.

Re:Why functional programming matters (1990) [pdf] by mafribe on Tuesday May 12, 2015 @12:39PM (#9532970)
Thanks. I know that "pure" is not thread-safe. I'm quite happy to consider the expressivity of Haskell's monadic approach to effects in a sequential setting first -- much easier to reason about. I wonder if anybody has investigated this expressivity problem. If not, there's an interesting problem waiting to be tackled.
Re:Why functional programming matters (1990) [pdf] by dllthomas on Tuesday May 12, 2015 @02:58PM (#9534047)
I don't see the problem. Pure code being automatically thread-safe is a boon. I would much rather be unable to write thread-unsafe code without noticing (and able to when I deliberately decide to).
Re:Why functional programming matters (1990) [pdf] by mafribe on Wednesday May 13, 2015 @01:19AM (#9536910)
My interest is in proving expressivity results. Such proofs are much easier in a sequential setting. Indeed, at this point I don't even have a strong intuition what exactly the expressivity limitations of Haskell's monadic effect control are.