我需要一种方法来根据类的特定实例有条件地应用函数。
我尝试使用Proxy对其输入类型进行注释:
class ApplyIf b where
applyIf :: Show b => proxy a -> (a -> a) -> b -> String
instance ApplyIf Int where
applyIf (p :: Proxy Int) f b = show (f b)
applyIf _ _ b = show b
instance ApplyIf String where
applyIf _ _ b = show b
main = do
putStrLn $ applyIf (Proxy:: Proxy Int) (*2) 1 -- 2
putStrLn $ applyIf (Proxy:: Proxy Int) (*2) "ok" -- ok
但是在第5行上出现“非法类型签名:'Proxy Int'错误”。
我是否应该使用其他一些机制,例如标记的,可键入的...?
答案 0 :(得分:3)
代理是一种不保存数据的类型,但具有任意类型(甚至种类)的幻像参数。
即在运行时,您无法确定自己是否有Proxy Int
,因此无法对此进行模式匹配。而不是Proxy
,您需要TypeRep
:
{-# LANGUAGE TypeApplications #-}
import Type.Reflection
class ApplyIf a where
applyIf :: Show b => TypeRep a -> (a -> a) -> b -> String
instance ApplyIf Int where
applyIf tr f b | tr == typeRep @Int = show (f b)
| otherwise = show b
(TypeApplications
需要@Int
)。您也可以使用typeOf (0 :: Int)
。
编辑:这会做什么?参见Data.Type.Equality
。
{-# LANGUAGE TypeApplications #-}
import Type.Reflection
import Data.Type.Equality
-- could have Typeable a constraint instead of a TypeRep a param
applyIf :: (Show b, Show c, Typeable b) => TypeRep a -> (a -> c) -> b -> String
applyIf tr f b =
case testEquality tr (typeOf b) of
Just Refl -> show (f b)
Nothing -> show b
main = do
putStrLn $ applyIf (typeRep @Int) (*2) 1 -- 2
putStrLn $ applyIf (typeRep @Int) (*2) "ok" -- ok
答案 1 :(得分:3)
你的意思是这样吗?
import Data.Typeable
applyIf :: (Show a, Typeable a, Show b, Typeable b) => (b -> b) -> a -> String
applyIf f x = case cast x of
Nothing -> show x
Just y -> show (f y)
main = do
putStrLn $ applyIf ((*2) :: Int -> Int) (1 :: Int)
putStrLn $ applyIf ((*2) :: Int -> Int) "ok"
在这里,我们使用Typeable
在运行时检查a
和b
是否是同一类型,这可以让我们应用f
还是不应用。