Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
GHC
GHC
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,273
    • Issues 4,273
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Merge Requests 413
    • Merge Requests 413
  • Requirements
    • Requirements
    • List
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
  • Security & Compliance
    • Security & Compliance
    • Dependency List
    • License Compliance
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Code Review
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #7080

Closed
Open
Opened Jul 16, 2012 by Simon Peyton Jones@simonpjDeveloper

Make RULES and SPECIALISE more consistent

This glasgow-haskell-users email thread describes the inconsistency between RULES and SPECIALISE pragmas. Consider

module Test where

import Data.Monoid
import Control.Monad.Writer.Strict

f :: Monad m => a -> m a
f = return

g :: Monoid w => a -> Writer w a
g = return

{-# RULES "f->g" f = g  #-}

{-# SPECIALISE f :: Monoid w => a -> Writer w a #-}

Here, the SPECIALISE pragma is accepted, but the RULE is rejected thus:

    Could not deduce (Monoid w) arising from a use of `g'
    from the context (Monad (WriterT w Identity))
      bound by the RULE "f->g" at Foo.hs:14:3-14
    Possible fix: add (Monoid w) to the context of the RULE "f->g"
    In the expression: g
    When checking the transformation rule "f->g"

Rejecting the RULE is quite right. On the LHS you have an application

    f (WriterT w Identity) d
  where d :: Monad (WriterT w Identity)

Recall that Writer w = WriterT w Identity. For the rewrite to work you have to rewrite this to

    g w d'
  where
    d' :: Monoid w

Well, how can you get a Monoid w dictionary from a Monad (WriterT w Identity)?

I was surprised that the SPECIALISE pragma worked, but here's what it does (you can see with -ddump-rules):

==================== Tidy Core rules ==================== "SPEC Foo.f" [ALWAYS]
    forall (@ a) (@ w) ($dMonoid :: Data.Monoid.Monoid w).
      Foo.f @ a
            @ (Control.Monad.Trans.Writer.Strict.WriterT
                 w Data.Functor.Identity.Identity)
            (Control.Monad.Trans.Writer.Strict.$fMonadWriterT
               @ w
               @ Data.Functor.Identity.Identity
               $dMonoid
               Data.Functor.Identity.$fMonadIdentity)
      = Foo.f_f @ a @ w $dMonoid

Ah! This rule will only match if the LHS is exactly

f (WriterT w Identity) ($fMonadWriterT w Identity dm $fMonadIdentity)

So it's a nested pattern match. That makes the LHS match less often; namely only when the dictionary argument to f is an application of $fMonadWriterT, the function that arises from the instance decl

    instance (Monoid w, Monad m) => Monad (WriterT w m) where

In exchange for matching less often, we now do get access to the (Monoid w) argument.

It is odd that this is inconsistent. Here is why. For a RULE, we must have a way to rewrite the LHS to an arbitrarily complicated RHS. For a SPECIALISE pragma

    SPECIALISE f :: spec_ty
where f's type is
    f :: poly_ty

we simply ask whether poly_ty is more polymorphic than spec_ty; that is, whether f can appear in a context requiring a value of type spec_ty. If so, we see what arguments f would need to do that, and that's the LHS pattern.

But

  • It's odd that the behaviour is inconsistent
  • The SPECIALISE rule is pretty fragile, beause it'll only match if the argument dictionary is constructed exactly as shown.

It's not clear to me what, if anything, to do about this, but this ticket records the issue.

Trac metadata
Trac field Value
Version 7.4.2
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
Assignee
Assign to
⊥
Milestone
⊥
Assign milestone
Time tracking
None
Due date
None
Reference: ghc/ghc#7080