[GHC] #14662: Partial type signatures + mutual recursion = confusion
GHC
ghc-devs at haskell.org
Thu Jan 11 21:52:47 UTC 2018
#14662: Partial type signatures + mutual recursion = confusion
-------------------------------------+-------------------------------------
Reporter: goldfire | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.2.2
Keywords: | Operating System: Unknown/Multiple
Architecture: | Type of failure: None/Unknown
Unknown/Multiple |
Test Case: | Blocked By:
Blocking: | Related Tickets:
Differential Rev(s): | Wiki Page:
-------------------------------------+-------------------------------------
I'm trying to understand better how partial type signatures interact with
mutual recursion. This is all in 8.4.1-alpha1.
Example 1:
{{{#!hs
f :: forall a. _ -> a -> a
f _ x = g True x
g :: forall b. _ -> b -> b
g _ x = f 'x' x
}}}
This works -- no problem.
Example 2:
{{{#!hs
f :: forall a. _ -> a -> a
f _ x = snd (g True 'a', x)
g :: forall b. _ -> b -> b
g _ x = f 'x' x
}}}
This fails, explaining that GHC inferred `g :: Bool -> a -> a` and that
`a` doesn't match `Char` (in the second argument of the call site in the
body of `f`). This is unsatisfactory because clearly `g` should be
''instantiated'' at `Char`. The manual does say that polymorphic recursion
isn't available with partial type signatures, and I suppose this is an
example of polymorphic (mutual) recursion.
Example 3:
{{{#!hs
f :: forall a. _ -> a -> a
f _ x = snd (g True 'a', x)
where
g :: forall b. _ -> b -> b
g _ y = f 'x' y
}}}
This is accepted. This is the same example as the last one, but now `g` is
local. It does not capture any variables (including type variables) from
`f`, so it seems to me that it should be equivalent to Example 2. But
somehow GHC is clever enough to accept.
Example 4:
{{{#!hs
thdOf3 (_, _, c) = c
f :: forall a. _ -> a -> a
f _ x = thdOf3 (g True 'a', g False 5, x)
where
g :: forall b. _ -> b -> b
g _ y = f 'x' y
}}}
This works, too. Note that `g` is applied at several different types, so
it really is being generalized.
Example 5:
{{{#!hs
f :: Int -> forall a. _ -> a -> a
f n _ x = snd (g n True 'a', x)
g :: Int -> forall b. _ -> b -> b
g n _ x = f n 'x' x
}}}
This is accepted. This is the same as Example 2, but each function now
takes an `Int`, which is simply passed back and forth. Evidently, when you
write the type non-prenex, polymorphic recursion is OK.
Example 6:
{{{#!hs
f :: Int -> forall a. _ -> a -> a
f n _ x = snd (f n True 'x', x)
}}}
This is accepted, even though it's blatantly using polymorphic recursion.
Example 7:
{{{#!hs
f :: forall a. _ -> a -> a
f _ x = snd (f True 'x', x)
}}}
This is rejected as polymorphically recursive.
--------------------------
Something is fishy here. It's not the explicit prenex `forall`s -- leaving
those out doesn't change the behavior. I guess my big question is this:
* If the user quantifies a partial type signature (either by using
`forall`, or just using an out-of-scope type variable and using Haskell's
implicit quantification), why can't we use polymorphic recursion with that
variable? I understand why we can't use polymorphic recursion with
wildcards.
-----------------------------------
A little background for context: I'm struggling (in my work on #14066)
with GHC's use of `SigTv`s for partial type signatures. I don't have a
better suggestion, but `SigTv`s never make me feel good.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14662>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list