Mic*_* Wu 1 polymorphism haskell
更具体地说,假设我有一些数据构造函数
data Foo = ... deriving Eq
Run Code Online (Sandbox Code Playgroud)
以及愚蠢的功能
f :: Eq a => a -> Bool
Run Code Online (Sandbox Code Playgroud)
如果变量a实际上是Foo类型,我希望f输出True.在所有其他情况下(即对于Eq的所有其他实例),我希望f输出False.
起初我想也许我可以为此目的定义一个新类型
class IsFoo a where
isFoo :: a -> Bool
Run Code Online (Sandbox Code Playgroud)
虽然为Foo编写一个IsFoo实例很容易,但显然我不想对所有类型为Eq的类型执行此操作.
在回答时,您可以假设Foo有很多构造函数,并且我不想在所有构造函数上进行模式匹配.我也不想使用Data.Typeable(我读过它的样式很糟糕).有没有办法以优雅和自然(wrt Haskell)的方式完成我想要的东西?
在我看来你不应该这样做.这对我来说似乎是一个严重的XY问题,因为Haskell的类型系统通常应该为你做这些事情.
但尽管如此,这是可能的.实现这一目标的最简单方法是使用类型类:
data Foo = A | B | C | D | ... | Z deriving Eq
class IsFoo a where
isFoo :: a -> Bool
instance IsFoo Foo where
isFoo = const True
instance IsFoo x where
isFoo = const False
Run Code Online (Sandbox Code Playgroud)
使用FlexibleInstances扩展,通过简单地返回True给定的类型参数,在类型Foo的实例中指定Foo并且使用任何其他类型的变量False调用时,可以节省一些工作isFoo.请注意,您还必须使用扩展OverlappingInstances,否则将isFoo使用类型的参数调用运行时错误,Foo因为程序将不知道要使用哪个实例.要启用这些扩展,只需包含
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
Run Code Online (Sandbox Code Playgroud)
在源文件的顶部.
仍然:我强烈建议尝试不同的方法解决您的问题,因为一般情况下您不必处理这种"低级"打字的东西.
如果这真的是你想要做的,我建议你使用Data.Typeable,因为它完全适合这个目的:
import Data.Maybe (isJust)
import Data.Typeable
isFoo :: (Typeable a) => a -> Bool
isFoo x = isJust (cast x :: Maybe Foo)
Run Code Online (Sandbox Code Playgroud)
坏风格的问题不是关于使用特定的库Data.Typeable.这是关于不正确使用Haskell的类型系统,特别是将其视为动态OO语言.如果您需要确定是否有某种泛型类型Foo,那么您在某处忘记了类型信息.但是在Haskell中,你总是在编译时有这个,所以不需要动态地确定它.
也许解释一下你想要实现的目标,可能会有一种更为惯用的方法.
| 归档时间: |
|
| 查看次数: |
138 次 |
| 最近记录: |