Forward compatibility (was Re: [Haskell-cafe] GHCi infers a type but refuses it as type signature)

On Tue, Jun 23, 2009 at 2:20 AM,
Simple: the definition of MonadState uses those extensions.
Thanks, yes it helps and explains all. :^)
I suppose then that if -XFlexibleContexts is indeed required by the standard libraries, it is a "safe" extension, meaning supported by all compilers? Are many such extensions de-facto standard that anyone can enable by default?
You should treat "all compilers" the same way as a universal quantifier in mathematics. It's not just all the compilers you know about, but all possible compilers. In which case the answer to your question is of course no. (Beware: incoming my "recurring rant of the month", which I am trying ferociously to cram down the throats of my peers :-p) By measuring your software's portability on this stricter criterion, you contribute to the exponential growth of our field. It means that *every *future compiler can compile your code for 10% less effort*. *A future innovation may rely on one such compiler, which means it can use your code 10% sooner -- which may be the difference between your good code being used and it being badly reimplemented (and future bug fixes in the new code does not benefit yours). And so on, ad infinitum. When you think about potability, think about it from the perspective of twenty years in the future. Fundeps are becoming obsolete now, will your code still work when they are gone? Will it still work when the typeclass resolution algorithm is obsoleted by a superior algorithm (I'm looking at you, Oleg! :-)? When Haskell is obsolete, how hard will it be to port? Of course, there is definitely a place for extensions -- we should be testing them, to help refine the language that will one day obsolete Haskell. A culture of extension users helps us to know that, for example, even though implicit params are cool, nobody cares. I think "works on all existing compilers" is a fine definition of "portable" -- let's just realize that there is a level of portability beyond that, a level which gives our whole field a little boost. </rant> Luke

Hi Luke,
Simple: the definition of MonadState uses those extensions. [Snip question: Is this extension supported by all compilers] You should treat "all compilers" the same way as a universal quantifier in mathematics. It's not just all the compilers you know about, but all possible compilers. In which case the answer to your question is of course no.
I think the reasoninging here is the following: If MonadState is part of the standard library and it needs this extension to work, then all compilers must support this extension. I'm not completely sure how "standard" the MonadState class is though. Also, it might be that there could be implementations of MonadState that do not use the extension? If the latter is not the case, so MonadState will always require this extension, than it seems that using the extension in your code gives you the same portability as using the MonadState class. Not using the extension to improve your portability only makes sense if you also stop using the MonadState class, right? Gr. Matthijs

Thanks for your answers. I still have a question, though...
I think the reasoninging here is the following: If MonadState is part of the standard library and it needs this extension to work, then all compilers must support this extension.
Yes, exactly, that was my point.
I'm not completely sure how "standard" the MonadState class is though. Also, it might be that there could be implementations of MonadState that do not use the extension?
And indeed, I understand from the next (Luke Palmer's) answer that the community does not fully agree on what should be standard:
However, your question is rather moot here, as you are using the *mtl. *It uses UndecidableInstances, whose blessing into the de facto standard would require as a precondition the batshit-insanity of the de facto community.
I personally use *transformers* as my monad library, as it is (as far as I know) the only Haskell 98 monad library on Hackage (you'll hardly notice the more explicit lifts, I promise!).
I just looked through Transformers and it does not define MonadState, indeed. Well... I am a beginner in haskell. I have detailed in the first post the very simplistic example I was trying to set up, the level of a beginner's tutorial. As anyone discovering a new language, I certainly did not intend to look so soon at compiler extensions. Now, trying to avoid duplicate code at this very level of simplicity seems to require compiler extensions! Here it is: - The MonadState type seems required to reuse the same code for "State s a" and "StateT s IO a". - MonadState needs compiler extensions and is implemented using the mtl library which seems to have drawbacks. So 1) How can I use transformers instead of the mtl? This is in no tutorial, and searchinf for "mtl" on the haskell wiki yields no result at all. 2) What should be the Haskell98-compatible type signature for my play2 function, instead of (MonadState [a] m, Eq a) => a -> m Bool ? Thanks again.

On Tue, Jun 23, 2009 at 6:05 PM, Eric Dedieu
So
1) How can I use transformers instead of the mtl? This is in no tutorial, and searchinf for "mtl" on the haskell wiki yields no result at all.
cabal install transformers (you need cabal-install to do this... consult #haskell if confused) perhaps: > ghc-pkg hide mtl (I think mtl and transformers fight over the Control.Monad module)
Then import Control.Monad.Trans.State instead of Control.Monad.State. All else should be well, if I am not forgetting something.
2) What should be the Haskell98-compatible type signature for my play2 function, instead of (MonadState [a] m, Eq a) => a -> m Bool ?
That depends on the monad library. In transformers it would be: (Monad m, Eq a) => a -> StateT [a] m Bool State s is just a type synonym for StateT s Identity, so this works for State as well. Luke

On Tue, Jun 23, 2009 at 6:05 PM, Eric Dedieu
Now, trying to avoid duplicate code at this very level of simplicity seems to require compiler extensions! Here it is:
On a higher level, in case you are interested, here's a description of how I would model your problem. Take this with a grain of salt: we are already in the area where different haskell vets will model this in different ways. This is one of many approaches... Instead of possibly tying the game to its side effects inside a monad, I would model the game as a pure data structure, and then have different interfaces just talk about the pure structure. Note: In the real world, things would be more polymorphic, but I'll keep it concrete for expository purposes: For example: newtype Game = MkGame [Char] empty :: Game empty = MkGame [] play :: Char -> Game -> (Bool, Game) play x (MkGame mvs) = (x `elem` moves, MkGame (x:mvs)) moves :: Game -> [Char] moves (MkGame mvs) = mvs These constitute the only interface you have to Game; it is immoral to use MkGame from here on out. If you were being rigorous, these would go into a module with export list (Game, empty, play, moves). Everything else is straightforward from here. The code you wished to reuse is in "play", hidden behind an abstraction barrier so the compiler may ensure that it is reused (because there is no other way to play a Game). State monads don't even enter the picture at this level. (The return type of Play is Game -> (Bool, Game), which is State Game Bool... but I would just choose not to notice that; the state structure isn't important enough here to formalize). Luke

On Jun 23, 2009, at 05:20 , Luke Palmer wrote:
obsolete now, will your code still work when they are gone? Will it still work when the typeclass resolution algorithm is obsoleted by a superior algorithm (I'm looking at you, Oleg! :-)? When Haskell is obsolete, how hard will it be to port?
This is the point at which 99% of programmers throw up their hands at the futility of trying to guess what lies 20 years in the future, and just writes the fscking code. I mean, you've just ruled out both Haskell98 *and* Haskell-with-extensions. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

On Tue, Jun 23, 2009 at 8:28 PM, Brandon S. Allbery KF8NH < allbery@ece.cmu.edu> wrote:
On Jun 23, 2009, at 05:20 , Luke Palmer wrote:
obsolete now, will your code still work when they are gone? Will it still work when the typeclass resolution algorithm is obsoleted by a superior algorithm (I'm looking at you, Oleg! :-)? When Haskell is obsolete, how hard will it be to port?
This is the point at which 99% of programmers throw up their hands at the futility of trying to guess what lies 20 years in the future, and just writes the fscking code. I mean, you've just ruled out both Haskell98 *and* Haskell-with-extensions.
What? I didn't mean to. In case I wasn't clear enough, by the typeclass algorithm, I mean the algorithm for inference with typeclasses -- the semantics would be the same. Many of Oleg's famous hacks are sensitive to the specific way GHC searches for instances, which I did intend to rule out. And "how hard will it be to port" is about the essence of the code. I'm trying to rule out code which is not correct and meaningul at its heart, but which may rely on syntactic tricks (eg. printf emulation, "Monads" which don't satisfy the laws just for the notation, ...), or operational tricks such as unsafeInterleaveIO. Code that has an air of a mathematical model is much more likely to be portable. I think typical Haskell code will end up having a much longer life than typical C code, even if Haskell dies when C is still in use. But a small fraction Haskell code is *just* Haskell code, and I try not to write that kind. Really, such mindfulness is a lot easier than it sounds, because we are using such a beautiful, essentially simple language. Luke
participants (4)
-
Brandon S. Allbery KF8NH
-
Eric Dedieu
-
Luke Palmer
-
Matthijs Kooijman