如何使用PackageImports扩展来“遮蔽”模块?

时间:2017-01-27 14:24:56

标签: haskell

我正在尝试使用PackageImports扩展程序“遮蔽”Scotty模块。

使用案例:对于使用库X的人,可以使instrumentedX可用。因此,只需将cabal文件中的X更改为instrumentedX,即可使用该库的检测版本,而无需对代码进行任何其他更改。

这是我要导出的模块,它与Scotty导出的原始模块具有相同的名称,即Web.Scotty.Trans

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PackageImports #-}

module Web.Scotty.Trans
  (
    module OS
  , get
  , post
  , put
  , delete
  , patch
  , options
  , addroute
  )
where

import qualified "scotty" Web.Scotty.Trans as OS hiding (get, post, put, delete, patch, options, addroute)
import qualified "scotty" Web.Scotty.Trans as S

import InstrumentedCore
import Control.Monad.Trans.Class(lift)

instrumentedAction original action = original action_
  where
    action_ = do
      st <- liftIO $ getCurrentTime
      result <- action
      en <- liftIO $ getCurrentTime
      logInstrumentationData InstrumentationData{instrStart=st, instrEnd=en, instrPayload=Render}
      return result


get route action = instrumentedAction (S.get route) action
post route action = instrumentedAction (S.post route) action
put route action = instrumentedAction (S.put route) action
delete route action = instrumentedAction (S.delete route) action
patch route action = instrumentedAction (S.patch route) action
options route action = instrumentedAction (S.options route) action
addroute method route action = instrumentedAction (S.addroute method route) action

这是我的cabal文件的样子。虽然我的包依赖于scotty,但它为自己使用了不同的包名,即instrumentedopaleye(不要进入语义 - 我也试图影响很多其他模块!)

name:                instrumentedopaleye
version:             0.1.0.0
synopsis:            Initial project template from stack
description:         Please see README.md
homepage:            https://github.com/githubuser/dashboard#readme
license:             BSD3
author:              Author name here
maintainer:          example@example.com
copyright:           2016 Author name here
category:            Web
build-type:          Simple
extra-source-files:  README.md
cabal-version:       >=1.10

library
  hs-source-dirs:      src
  exposed-modules:     InstrumentedOpaleye
                     , Instrumented
                     , InstrumentedOpaleye.Internal.PGTypes
                     , InstrumentedOpaleye.Internal.Column
                     , InstrumentedOpaleye.Internal.RunQuery
                     , InstrumentedOpaleye.Internal.HaskellDB.PrimQuery
                     , InstrumentedLucid
                     , Web.Scotty.Trans
                     , InstrumentedCore
  build-depends:       base >= 4.7 && < 5
                     , opaleye
                     , profunctors
                     , product-profunctors
                     , postgresql-simple
                     , mtl
                     , time
                     , stm
                     , text
                     , uuid
                     , lucid
                     , scotty
                     , transformers
  default-language:    Haskell2010

实际错误

当我尝试在GHCi中导入我的Web.Scotty.Trans版本时会发生什么。鉴于我已明确导入我的Web.Scotty.Trans版本,为什么GHCi在解决get函数时感到困惑?即使:browse Web.Scotty.Trans感到困惑。

Saurabhs-MacBook-Pro:instrumentedopaleye saurabhnanda$ stack exec ghci
GHCi, version 8.0.1: http://www.haskell.org/ghc/  :? for help
Prelude> :set -fobject-code
Prelude> :set -XPackageImports
Prelude> import "instrumentedopaleye" Web.Scotty.Trans
Prelude Web.Scotty.Trans> :i get

<interactive>:1:1: error:
    Ambiguous interface for ‘Web.Scotty.Trans’:
      it was found in multiple packages:
      scotty-0.11.0 instrumentedopaleye-0.1.0.0
Prelude Web.Scotty.Trans> :browse Web.Scotty.Trans

<no location info>: error:
    Ambiguous module name ‘Web.Scotty.Trans’:
      it was found in multiple packages:
      scotty-0.11.0@scotty-0.11.0-2sNTuGP3mb3FV66hlreoEd instrumentedopaleye-0.1.0.0@instrumentedopaleye-0.1.0.0-EAOrgrhUGi83yaJJ8gDGX4

2 个答案:

答案 0 :(得分:2)

我在之前看到这种行为甚至你做了一个包合格的导入。例如,如果我之前已经安装了堆栈cryptonitecrypto-api,那么

> stack exec ghci
$ :browse Crypto.Random

导致ambiguous module name错误。这是我遇到的一个问题;我的解决方案是使用-hide-package标志:

> stack exec ghci
$ :set -hide-package cryptonite
$ :browse Crypto.Random

作为额外奖励,您根本不再需要PackageImports:ghci完全忽略cryptonite

答案 1 :(得分:1)

根据[crockeea的回答] [1]

我没有明确地隐藏scotty而无法在GHCi中完成这项工作

此外,由于[Haskell的模块限制] [2],无法重新导出合格的导入。因此,这就是我如何设法解决我最初的影子scotty问题:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PackageImports #-}

module Web.Scotty.Trans
  (
    module Web.Scotty.Trans -- which is the current module
  , module Web.Scotty.TransOriginal -- the original module MINUS the shadowed methods
  )
where

import Web.Scotty.TransOriginal
import qualified "scotty" Web.Scotty.Trans as S

import InstrumentedCore
import Control.Monad.Trans.Class(lift)

instrumentedAction original action = original action_
  where
    action_ = do
      st <- liftIO $ getCurrentTime
      result <- action
      en <- liftIO $ getCurrentTime
      logInstrumentationData InstrumentationData{instrStart=st, instrEnd=en, instrPayload=Render}
      return result


get route action = instrumentedAction (S.get route) action
post route action = instrumentedAction (S.post route) action
put route action = instrumentedAction (S.put route) action
delete route action = instrumentedAction (S.delete route) action
patch route action = instrumentedAction (S.patch route) action
options route action = instrumentedAction (S.options route) action
addroute method route action = instrumentedAction (S.addroute method route) action

样板 Web.Scotty.TransOriginal只需要绕过Haskell重新导出合格导入的限制:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PackageImports #-}

module Web.Scotty.TransOriginal
  (
    module Web.Scotty.Trans
  )
where

import "scotty" Web.Scotty.Trans hiding (get, post, put, delete, patch, options, addroute)