[Haskell] Haskell's type inference considered harmful [Re: A riddle...]

Christian Höner zu Siederdissen choener at tbi.univie.ac.at
Mon Jul 16 21:38:03 CEST 2012


Hi Andreas,

formally, there is only one problem here: you either need to have NoMono
on, or give a general type for your function. I tend to give types for
everything top-level. This takes care of 1+2.

3 is actually completely ok, as 181935629 === 7693 | 2^16, as the notes
for Data.Word states (all arithmetic is performed modulo 2^n). And that
is actually what I would want and except for a "high-performance" data
type, or any data type that states that it is based on operations
"modulo k".

What would make sense for you (I am doing this for some stuff, too) is
to have a smart ctor that checks its input (say indexing with
non-negative indices).

Btw, you should also be able to fix the algorithm below, by performing
the calculation using Integer, and only at the last step transforming to
Word16. Of course, this just means that internally (fromIntegral
181935629) returns an Integer, while now it will return a Word16 in the
problematic version.

Btw., for strings, this is less of a problem as you have to use the
OverloadedStrings extension to get (fromString "bla"), while
(fromIntegral 1) is always on. Having OverloadedNumbers could be what
you would like? (Or, actually NoOverloadedNumbers since most people
probably want this behavior?)

Gruss,
Christian



* Andreas Abel <andreas.abel at ifi.lmu.de> [16.07.2012 20:22]:
> Congratulations to all that solved the riddle so quickly.  (First
> answer in only 8 Minutes!)  Now to the point of the exercise:
> Shocking realizations.
> 
>   1. Haskell's type inference is NON-COMPOSITIONAL!
> 
> In the riddle below, I am defining two things f ("rgbliste") and g
> ("farbliste").  Even though they are not strongly connected, but g
> comes after f in the definition order, the code of g influences the
> type of f.  THAT'S WRONG! :-(
> 
> It gets worse:
> 
>   2. DEAD CODE changes a program's result!
> 
> Yes indeed.  Dead code ("farbliste") in the source cannot be removed
> safely.  And:
> 
>   3. Haskell "casts" 181935629 to Word16 value 7693 WITHOUT WARNING!
> 
> Needless to say, these are serious problems for leading-edge
> strongly typed language.  The experts are probably aware of this.
> But I awoke harshly from a sweet dream.
> 
> Issue 3 is quite harmful and reminds me more of C than of a strongly
> typed language.  Fixing this is not trivial.  The problem is that
> all numeric constants have type Num a => a, and of course, type
> variable a can be instantiated to Int Word16 or whatever.  Numeric
> constants need to inhabit subclasses of Num, e.g., Word16, Int and
> Integer /classes/ to make this behavior go away.
> 
> Issues 1/2 go away with
> 
>   {-# LANGUAGE NoMonomorphismRestriction #-}
> 
> (thx to Christian who pointed me to this).  I wonder why this is not
> on by default?!  There seems to be an unresolved dispute about
> this... http://hackage.haskell.org/trac/haskell-prime/wiki/NoMonomorphismRestriction
> 
> But even with MonomorphismRestriction, issue 1/2 are avoidable with
> a more refined approach to type meta variables in the Haskell type
> inference:  After type-checking a strongly connected component, type
> meta variables created for this part of the Haskell program should
> not be instantiated in the (topologically) later defined parts of
> the program.  YOU DON'T WANT THE USE OF A FUNCTION INFLUENCE ITS
> DEFINITION!  There are two alternatives what to do with remaining
> meta-variables of a SCC:
> 
>   1. With monomorphism restriction: instantiate to the "best type".
>      In our example below, Haskell chooses Integer.
> 
>   2. Without monomorphism restriction: generalize.
> 
> Choice 1 will give an error in the program below, but i rather have
> an error than a silent change of behavior of my program!
> 
> Cheers,
> Andreas
> 
> P.S.: In Agda, in the situation of unsolved metas in an "SCC" (a
> mutual block), these metas are just frozen, triggering typing errors
> later (since Agda cannot generalize).  The user has to go back an
> insert more type annotations.  But this is safe, whereas silent late
> instantiation breaks compositionality.
> 
> 
> 
> On 16.07.2012 17:25, Andreas Abel wrote:
> >Today a student came to me with a piece of code that worked it executed
> >by itself, but produced different result in the context of his larger
> >problem.  We cut down the example to the following:
> >
> >>import Graphics.UI.Gtk
> >>
> >>-- should produce [(26471,0,65535),...
> >>rgbliste =
> >> (map (\ i ->
> >>  let rb = 5 * (mod (mod 181935629 (4534+i)) 100)-250+128 in
> >>  let gb = 5 * (mod (mod 128872693 (5148+i)) 100)-250+128 in
> >>  let bb = 5 * (mod (mod 140302469 (7578+i)) 100)-250+128 in
> >>  let r = min 255 $ max 0 rb in
> >>  let g = min 255 $ max 0 gb in
> >>  let b = min 255 $ max 0 bb in
> >>  (r*257,g*257,b*257)) [0..])
> >>
> >>--farbliste = map (\ (r,g,b) -> Color r g b) rgbliste
> >>
> >>main :: IO ()
> >>main = do
> >>  print $ head rgbliste
> >
> >If you run it, it prints (26471,0,65535).
> >If you uncomment the def. of farbliste, it prints (44461,65535,65535).
> >
> >I was surprised.  What is going on?
> >
> >Cheers,
> >Andreas
> >
> 
> 
> -- 
> Andreas Abel  <><      Du bist der geliebte Mensch.
> 
> Theoretical Computer Science, University of Munich
> Oettingenstr. 67, D-80538 Munich, GERMANY
> 
> andreas.abel at ifi.lmu.de
> http://www2.tcs.ifi.lmu.de/~abel/
> 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://www.haskell.org/pipermail/haskell/attachments/20120716/211445c8/attachment.pgp>


More information about the Haskell mailing list