带类约束的GHC重写规则

14
我已经成功将以下重写规则添加到通道中:

无问题:

{-# RULES "ConduitM: lift x >>= f" forall m f.
    lift m >>= f = ConduitM (PipeM (liftM (unConduitM . f) m))
  #-}

我试图为liftIO添加类似的重写规则

{-# RULES "ConduitM: liftIO x >>= f" forall m f.
    liftIO m >>= f = ConduitM (PipeM (liftM (unConduitM . f) (liftIO m)))
  #-}

然而,当我尝试这么做时,GHC 给了我以下错误信息:

Data/Conduit/Internal/Conduit.hs:1025:84:
    Could not deduce (Monad m) arising from a use of ‘liftM’
    from the context (Monad (ConduitM i o m), MonadIO (ConduitM i o m))
      bound by the RULE "ConduitM: liftIO x >>= f"
      at Data/Conduit/Internal/Conduit.hs:1025:11-118
    Possible fix:
      add (Monad m) to the context of the RULE "ConduitM: liftIO x >>= f"
    In the first argument ofPipeM’, namely
      ‘(liftM (unConduitM . f) (liftIO m))’
    In the first argument ofConduitM’, namely
      ‘(PipeM (liftM (unConduitM . f) (liftIO m)))’
    In the expression:
      ConduitM (PipeM (liftM (unConduitM . f) (liftIO m)))

Data/Conduit/Internal/Conduit.hs:1025:108:
    Could not deduce (MonadIO m) arising from a use of ‘liftIO’
    from the context (Monad (ConduitM i o m), MonadIO (ConduitM i o m))
      bound by the RULE "ConduitM: liftIO x >>= f"
      at Data/Conduit/Internal/Conduit.hs:1025:11-118
    Possible fix:
      add (MonadIO m) to the context of
        the RULE "ConduitM: liftIO x >>= f"
    In the second argument of ‘liftM’, namely ‘(liftIO m)’
    In the first argument ofPipeM’, namely
      ‘(liftM (unConduitM . f) (liftIO m))’
    In the first argument ofConduitM’, namely
      ‘(PipeM (liftM (unConduitM . f) (liftIO m)))’

我不知道是否有任何语法可以让我指定这样的上下文到重写规则中。有没有办法实现这个呢?

2个回答

12

您可以在规则中使用约束条件来指定参数的类型,例如:

{-# RULES "ConduitM: liftIO x >>= f" forall m (f :: (Monad n, MonadIO n) => CounduitM i o n r).
    liftIO m >>= f = ConduitM (PipeM (liftM (unConduitM . f) (liftIO m)))
  #-}

(我还没有测试它,因为我没有安装涉及的软件包,但就我理解的类型而言,应该可以工作,我想。)


1

我正在尝试找出如何实现将约束条件添加到重写规则中的类似效果。使用相同的语法,我能够让GHC编译通过,但显然,在这种情况下,重写规则根本不会被触发。

以下是一个简单的例子:

#!/usr/bin/env stack
-- stack --resolver lts-7.14 exec -- ghc -O -ddump-rule-firings
module Main where

import Prelude as P
import System.Environment (getArgs)


class Num e => Power e where
  (^:) :: Integral a => e -> a -> e

instance Power Double where
  (^:) x y = go 0 1 where
    go n acc | n < y = go (n+1) (acc*x)
             | n > y = go (n-1) (acc/x)
             | otherwise = acc

main :: IO ()
main = do
  [xStr] <- getArgs
  let x = read xStr :: Double
  print (x ^ 24)

{-# RULES
 "1. Test ^" forall (x :: Power x => x) n. x ^ n = x ^: n;
 "2. Test ^" forall x n. (x :: Double) ^ n = x ^: n 
 #-} 

即使第二条规则被移除,第一条规则也永远不会触发。这里有一个类似的SO问题,回答了为什么它不会触发: GHC重写规则为类型类专门化函数

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接