Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,869
    • Issues 4,869
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 456
    • Merge requests 456
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #21376
Closed
Open
Created Apr 11, 2022 by pbrisbin@pbrisbin

Type synonym with forall causes point-free code to not be equivalent

Summary

In GHC 9.0.2, it seems that using a point-free style doesn't work when a certain kind of type is involved.

This fails to compile (full details below):

limitRetries :: Natural -> RetryPolicy
limitRetries = Retry.limitRetries . fromIntegral

-- Given,
-- Retry.limitRetries :: Int -> RetryPolicy
-- type RetryPolicy = forall m. RetryPolicyM m

While this works fine:

limitRetries :: Natural -> RetryPolicy
limitRetries x = Retry.limitRetries $ fromIntegral x

As a relatively compiler-naive Haskell user, I wouldn't expect code with and without a point here to behave any differently, so I'm reporting this as a bug.

Also, HLint will automatically eta-reduce away a point, so this is a new avenue by which it can break your code.

Steps to reproduce

This error first hit me when upgrading a project using the retry library, so I've pared down my repro from there. I'm also using stack because it makes it trivial to ensure someone can run this at all the exact versions as I'm seeing.

repro.hs

{-# LANGUAGE RankNTypes #-}

module Control.Retry
    ( main
    ) where

import Prelude

import Numeric.Natural

newtype RetryPolicyM m = RetryPolicyM { getRetryPolicyM :: () -> m (Maybe Int) }

type RetryPolicy = forall m . Monad m => RetryPolicyM m

limitRetries :: Int -> RetryPolicy
limitRetries = undefined

limitRetries' :: Natural -> RetryPolicy
limitRetries' = limitRetries . fromIntegral

main :: IO ()
main = putStrLn "hi"
% stack --resolver lts-19.3 runhaskell -- repro.hs

repro.hs:16:16: error:
    • Couldn't match expected type ‘Int -> RetryPolicy’
                  with actual type ‘a0’
      Cannot instantiate unification variable ‘a0’
      with a type involving polytypes: Int -> RetryPolicy
    • In the expression: undefined
      In an equation for ‘limitRetries’: limitRetries = undefined
   |
16 | limitRetries = undefined
   |                ^^^^^^^^^

repro.hs:19:17: error:
    • Couldn't match type ‘c0’ with ‘RetryPolicy’
      Expected: Int -> c0
        Actual: Int -> RetryPolicy
      Cannot instantiate unification variable ‘c0’
      with a type involving polytypes: RetryPolicy
    • In the first argument of ‘(.)’, namely ‘limitRetries’
      In the expression: limitRetries . fromIntegral
      In an equation for ‘limitRetries'’:
          limitRetries' = limitRetries . fromIntegral
   |
19 | limitRetries' = limitRetries . fromIntegral

Expected behavior

The code should compile.

GHC 8.10 does not exhibit this behavior:

% stack --resolver lts-18.28 runhaskell -- repro.hs
hi

With GHC 9, you have to add points to both of these:

- limitRetries = undefined
+ limitRetries x = undefined x
- limitRetries' = limitRetries . fromIntegral
+ limitRetries' x = limitRetries $ fromIntegral x
% stack --resolver lts-19.3 runhaskell -- repro.hs
hi

Environment

  • GHC version used: 9.0.2 and 9.2.2

Optional:

  • Operating System: Arch Linux
  • System Architecture:
% uname -a
Linux prince 5.16.14-arch1-1 #1 SMP PREEMPT Fri, 11 Mar 2022 17:40:36 +0000 x86_64 GNU/Linux
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking