
Greetings. Say I have the following function, adapted from Pierce, Types and Programming languages: f n () = (n, f (n + 1)) Now, this function fails to typecheck in ghc 6.0.1 because the subexpression f (n + 1) has the infinite type t = () -> (t1, t) And so I assume (perhaps wrongly?) that f is ill-typed in Haskell 98. I have two questions: 1. How can I tell from the Haskell 98 Revised Report that this function isn't allowed? The discussions of typing in the Report generally defer to the ``standard Hindley-Milner analysis.'' Is this really enough to tell that the function isn't well-typed in Haskell? I concede that I haven't read the cited Hindley and Damas/Milner papers, but it seems like there might be more to say about what is and isn't allowed. 2. Is there by chance a compiler option for ghc that causes the restriction to be dropped? I don't need this kind of function for anything practical (and I realize I can get an equivalent effect with an algebraic datatype). I'm just trying to figure out what typing restrictions (if any) are implicitly assumed in the Report. (Generally, this is the kind of stuff I don't know, as a relative newcomer to fp.) Regards, Jeff Scofield (PhD) Seattle

1. How can I tell from the Haskell 98 Revised Report that [a function with an infinite type] isn't allowed? The discussions of typing in the Report generally defer to the ``standard Hindley-Milner analysis.''
1) The only way to write the recursive type you want in Haskell is using type synonyms. 2) The section describing type synonyms (4.2.2) explicitly rules it out. -- Alastair Reid www.haskell-consulting.com

Say I have the following function, ... :
f n () = (n, f (n + 1)) ... I have two questions:
1. How can I tell from the Haskell 98 Revised Report that this function isn't allowed? The discussions of typing in the Report generally defer to the ``standard Hindley-Milner analysis.''
In your example, if we assume that "f" has type, say, "a->()->(a,b)", for some "a","b", then it is used, in its own definition, with type "a->()->b". In the Hindley-Damas/Milner type system, there is no "polymorphic recursion": a variable being defined may not be used polymorphically inside its own definition. In other words, for typing its own definition, a variable is assumed to have a simple (non-quantified) type. Even in the Milner-Mycroft type system, where we have polymorphic recursion (a variable may be used polymorphically in its own definition), this expression could not be typed, because (informally speaking) a polymorphic type may only be instantiated, and "a->()->b" is not (cannot be) an instance of "a->()->(a,b)", for any "a","b". Hope that helps. Cheers, Carlos
Is this really enough to tell that the function isn't well-typed in Haskell? I concede that I haven't read the cited Hindley and Damas/Milner papers, but it seems like there might be more to say about what is and isn't allowed.
2. Is there by chance a compiler option for ghc that causes the restriction to be dropped?
I don't need this kind of function for anything practical (and I realize I can get an equivalent effect with an algebraic datatype). I'm just trying to figure out what typing restrictions (if any) are implicitly assumed in the Report. (Generally, this is the kind of stuff I don't know, as a relative newcomer to fp.)
Regards,
Jeff Scofield (PhD) Seattle _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

f n () = (n, f (n + 1))
In your example, if we assume that "f" has type, say, "a->()->(a,b)", for some "a","b", then it is used, in its own definition, with type "a->()->b".
Oops, should be: ... then it is used ... with type "a->b" (or Num a=>a->b).
... "a->()->b" is not (cannot be) an instance of "a->()->(a,b)" ...
Should be: "a->b" cannot be an instance of "a->()->(a,b)".

camarao@dcc.ufmg.br wrote:
Say I have the following function, ... :
f n () = (n, f (n + 1)) ... I have two questions:
1. How can I tell from the Haskell 98 Revised Report that this function isn't allowed? The discussions of typing in the Report generally defer to the ``standard Hindley-Milner analysis.''
In your example, if we assume that "f" has type, say, "a->()->(a,b)", for some "a","b", then it is used, in its own definition, with type "a->b".
This is true, but things typecheck OK as long as b = () -> (a, b) This is the so-called infinite type that I'm asking about. (You can get the above definition of f to typecheck and work as expected in Ocaml if you use the -rectypes flag mentioned in another message. So there's nothing inherently absurd about the definition of f. (Also, I just transcribed it from Pierce!))
In the Hindley-Damas/Milner type system, there is no "polymorphic recursion": a variable being defined may not be used polymorphically inside its own definition. In other words, for typing its own definition, a variable is assumed to have a simple (non-quantified) type.
Even in the Milner-Mycroft type system, where we have polymorphic recursion (a variable may be used polymorphically in its own definition), this expression could not be typed, because (informally speaking) a polymorphic type may only be instantiated, and "a->b" is not (cannot be) an instance of "a->()->(a,b)", for any "a","b".
As long as you allow infinite types, there is no polymorphic recursion (as I understand it). I'm definitely not arguing that these types should be allowed in Haskell. I'm wondering how to tell, as a relative newcomer to Haskell, that they aren't allowed. Possibly the answer is that these types are not allowed by the standard Hindley-Milner analysis and that I just need to read the papers cited in the Haskell Report. I was hoping to avoid this because reading such papers is very hard! I guess I'm also pointing out that I (as a newcomer) can't easily tell just from the Report that these types are forbidden in Haskell. In other words, I can't easily tell which recursive types are OK and which aren't. For whatever this is worth. (As I say, the restriction on type synonym declarations is very suggestive, but it really doesn't seem to apply to all types in a module, just to type synonyms.) Regards, Jeff Scofield

On 2003-12-08T12:42:46-0800, Jeffrey A. Scofield wrote:
b = () -> (a, b) [...] I'm wondering how to tell, as a relative newcomer to Haskell, that they aren't allowed.
I think the rule you're looking for is the following: Don't equate a type variable with something that contains that type variable. This is known as the "occurs check". This rule prohibits "equi-recursive" types like "b" above, but not "iso-recursive" types like data List a = Nil | Cons a (List a) because the type "List a" is merely isomorphic to something containing "List a", but not equal to it. -- Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig International Human Rights Day * 2003-12-10 * http://www.un.org/rights/ What if All Chemists Went on Strike? (science fiction) http://www.iupac.org/publications/ci/2003/2506/iw3_letters.html

Ken Shan wrote:
I think the rule you're looking for is the following: Don't equate a type variable with something that contains that type variable. This is known as the "occurs check". This rule prohibits "equi-recursive" types like "b" above, but not "iso-recursive" types like
data List a = Nil | Cons a (List a)
because the type "List a" is merely isomorphic to something containing "List a", but not equal to it.
Thanks, this is great. I understand (more or less) about equi- vs. iso-recursion from Pierce. The point (I assume) is that there is a natural distinction between the two cases, so that the restriction on infinite types (but not all recursive types) falls out fairly naturally from the Hindley-Milner analysis. (Thanks to everybody who responded.) Regards, Jeff Scofield Seattle

Hello,
There is a thread on comp.lang.functional that talks about why haskell
does not support recursive types:
http://groups.google.com/groups?q=ocaml+rectypes&hl=en&lr=lang_en&ie=UTF-8&oe=UTF-8&safe=off&selm=8giqpt%24oee%241%40rivesaltes.inria.fr&rnum=1
(searching for 'ocaml rectypes' on google groups turns up a number of
useful threads about the joys and dangers of allowing recursive types).
Jeremy Shaw.
At Wed, 3 Dec 2003 14:07:03 -0800,
Jeffrey A. Scofield
Greetings.
Say I have the following function, adapted from Pierce, Types and Programming languages:
f n () = (n, f (n + 1))
Now, this function fails to typecheck in ghc 6.0.1 because the subexpression f (n + 1) has the infinite type t = () -> (t1, t) And so I assume (perhaps wrongly?) that f is ill-typed in Haskell 98.
I have two questions:
1. How can I tell from the Haskell 98 Revised Report that this function isn't allowed? The discussions of typing in the Report generally defer to the ``standard Hindley-Milner analysis.'' Is this really enough to tell that the function isn't well-typed in Haskell? I concede that I haven't read the cited Hindley and Damas/Milner papers, but it seems like there might be more to say about what is and isn't allowed.
2. Is there by chance a compiler option for ghc that causes the restriction to be dropped?
I don't need this kind of function for anything practical (and I realize I can get an equivalent effect with an algebraic datatype). I'm just trying to figure out what typing restrictions (if any) are implicitly assumed in the Report. (Generally, this is the kind of stuff I don't know, as a relative newcomer to fp.)
Regards,
Jeff Scofield (PhD) Seattle

Jeremy Shaw wrote:
There is a thread on comp.lang.functional that talks about why haskell does not support recursive types:
(searching for 'ocaml rectypes' on google groups turns up a number of useful threads about the joys and dangers of allowing recursive types).
I hadn't yet gotten around to wondering about the tradeoffs, but now that you mention it these are interesting references. Thanks. (Also, if I want to play around with the examples in Pierce, I can use ocaml -rectypes. Thanks for pointing this out.) Regards, Jeff Scofield

Jeffrey A. Scofield wrote:
Say I have the following function, adapted from Pierce, Types and Programming languages:
f n () = (n, f (n + 1))
But a simple modification seems to cures the problem:
newtype W = W (Int, () -> W)
f n () = W (n, f (n + 1))
w2list (W (n,f)) = n:(w2list $ f ())
*Main> take 5 $ w2list (f 7 ()) [7,8,9,10,11] It works in Haskell98. Actually, at first I thought your problem is more complex. I thought it requires existential quantification to get the infinite type:
{-# OPTIONS -fglasgow-exts #-}
-- Emulating Peano integers
data W = forall a. (Show a) => W a
instance Show W where show (W a) = show a
f 0 = W ([]::[()]) f n = case f (n-1) of (W x) -> W [x]
*Main> f 5 [[[[[[]]]]]]
participants (6)
-
Alastair Reid
-
camarao@dcc.ufmg.br
-
Jeffrey A. Scofield
-
Jeremy Shaw
-
Ken Shan
-
oleg@pobox.com