我想将isShowable
函数编写为此代码的一部分。
data MaybeShowable = forall a . Show a => Showable a | Opaque
f :: (Data d) => d -> String
f x = case isShowable x of
Showable s -> show s
Opaque -> "<<OPAQUE>>"
isShowable :: (Data d) => d -> MaybeShowable
isShowable = ???
使用Data
实例可以实现吗?如果没有,最好的方法是什么?
注意:如果没有其他选项,我愿意为此解决这个版本,该版本仅适用于通过导入到定义isShowable
的模块可见的类型类实例
答案 0 :(得分:4)
我不确定你的真实目的是什么,但看起来你想将Java习惯嵌入Haskell。
如上所述in other SO question你正在做的事情将变成反模式。
您已添加澄清说明:
如果我愿意解决“通过导入到
isShowable
定义的模块”可见的类型类实例。
为什么不包装你的类型:
data MaybeShowable a where
Showable :: forall b. Show b => b -> MaybeShowable b
Opaque :: forall b. b -> MaybeShowable b
instance Show (MaybeShowable a) where
show (Showable x) = show x
show (Opaque x) = "<<OPAQUE>>"
让您的功能在MaybeShowable a
上运行,而不是普通a
。
然而这仍然是丑陋的。直接在Show a => a
或a
上操作是不是更容易。
其他方法是尽早捕获Show a
字典,即具有数据类型:
data MaybeShowable a = Showable a String -- Or even Showable a (a -> String)
| Opaque a
instance Show (MaybeShowable a) where
show (Showable x s) = s
show (Opaque x) = "<<OPAQUE>>"
wrapShow :: Show a => a -> MaybeShowable a
wrapShow x = Showable x (show x) -- Showable x show
wrapOpaque :: a -> MaybeShowable a
wrapOpaque = Opaque
这种方法的变化用于例如QuickCheck's forAll
。那部分是Haskell98。那里show x
被关闭到关闭,可能执行或不执行。懒惰是关键点!
答案 1 :(得分:2)
您可以使用模板haskell询问哪些实例可用:
module IsInstance where
import Language.Haskell.TH; import Data.Typeable
import Data.Generics; import Data.Monoid
-- $(isInst ''Show) :: Typeable a => a -> Bool
isInst :: Name -> ExpQ
isInst className = do
ClassI _ insts <- reify className
ClassI _ typeableInsts <- reify ''Typeable
let typeOfs = [ [| typeRep (Proxy :: Proxy $(return ty)) |]
| InstanceD _ (AppT _ ty) _ <- insts,
hasNoVarT ty,
or [ ty_ == ty | InstanceD _ (AppT _ ty_) _ <- typeableInsts ] ]
[| \ val -> typeOf val `elem` $(listE typeOfs) |]
hasNoVarT xs = getAll $ everything
(<>)
(mkQ mempty (\ x -> case x of
VarT {} -> All False
_ -> mempty))
xs
$(isInst ''Show) (1 :: Int)
是真的,但不幸的是
$(isInst ''Show) (1 :: Rational)
为false,因为此处使用==
并未说明Show (Ratio a)
的实例可以与type Rational = Ratio Integer
一起使用。因此,完整的解决方案必须知道如何选择实例。