Haskell instanceof 模拟?
Haskell instanceof analogue?
我是 Haskell 的新手,所以我的问题可能很愚蠢。
我想要一个函数
show2 :: (Show a) => a -> String
对于任何 a
,这将 return show a
,但如果 a 本身是 String
,则 a
。
我该如何实施?
P.S。如果这个功能已经在某个地方实现了,那就太好了,但我还是想看一个实现的例子。
您可以使用 Data.Typeable
中的 cast
show2 :: (Typeable a, Show a) => a -> String
show2 s = maybe (show s) id ms
where ms = cast s :: Maybe String
你可以用这段肮脏和危险的代码来做到这一点:
class Showable a where
show2 :: a -> String
instance Showable String where
show2 = id
instance (Show a) => Showable a where
show2 = show
您需要 -XOverlappingInstances -XFlexibleInstances -XUndecidableInstances
来编译和使用它。
*Main> show2 "abc"
"abc"
*Main> show2 3
"3"
Haskell 的设计方式与 instanceof
检查的概念非常相反。 Haskell 的设计没有包含这种运行时类型检查,因为 Haskell 非常注重强大的编译时保证:函数不应该在运行时了解其参数的类型比它在编译时知道的更精确。
这并不意味着该功能在 Haskell 中不存在——Lee 的回答演示了如何做到这一点——但在 Haskell 中,这是一个 opt-in 由 库 提供的特性,不是语言的核心部分(不像 Java 这样的语言,它是始终存在的核心特性——你可以'选择退出!)。
请注意,即使在面向对象编程中,instanceof
运算符也是有争议的。许多面向对象的程序员强烈反对使用它。几个例子(数百个):
- use of "Instance of" in java
- Avoiding instanceof in Java
- http://smsohan.com/blog/2011/11/01/using-instanceof-is-mostly-code-smell/
- http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism
- http://www.javapractices.com/topic/TopicAction.do?Id=31
- http://www.artima.com/interfacedesign/PreferPoly.html
所有这些中的建议往往是相同的:与其使用测试引用的类型并根据它切换到不同的行为,不如使用多态性:定义一个接口或 class您想要的操作的方法,并让您使用 instanceof
测试的对象实现他们自己的该方法版本以做正确的事情。
这条建议可以直接翻译成Haskell:
- 定义你自己的类型class来代表你想要的行为
- 为您感兴趣的每种类型实施此类型 class,并为每种类型实现正确的行为。
所以,你可以这样做:
class ToString a where
toString :: a -> String
instance ToString String where
toString str = str
instance ToString Integer where
toString i = show i
-- ...
我是 Haskell 的新手,所以我的问题可能很愚蠢。
我想要一个函数
show2 :: (Show a) => a -> String
对于任何 a
,这将 return show a
,但如果 a 本身是 String
,则 a
。
我该如何实施?
P.S。如果这个功能已经在某个地方实现了,那就太好了,但我还是想看一个实现的例子。
您可以使用 Data.Typeable
cast
show2 :: (Typeable a, Show a) => a -> String
show2 s = maybe (show s) id ms
where ms = cast s :: Maybe String
你可以用这段肮脏和危险的代码来做到这一点:
class Showable a where
show2 :: a -> String
instance Showable String where
show2 = id
instance (Show a) => Showable a where
show2 = show
您需要 -XOverlappingInstances -XFlexibleInstances -XUndecidableInstances
来编译和使用它。
*Main> show2 "abc"
"abc"
*Main> show2 3
"3"
Haskell 的设计方式与 instanceof
检查的概念非常相反。 Haskell 的设计没有包含这种运行时类型检查,因为 Haskell 非常注重强大的编译时保证:函数不应该在运行时了解其参数的类型比它在编译时知道的更精确。
这并不意味着该功能在 Haskell 中不存在——Lee 的回答演示了如何做到这一点——但在 Haskell 中,这是一个 opt-in 由 库 提供的特性,不是语言的核心部分(不像 Java 这样的语言,它是始终存在的核心特性——你可以'选择退出!)。
请注意,即使在面向对象编程中,instanceof
运算符也是有争议的。许多面向对象的程序员强烈反对使用它。几个例子(数百个):
- use of "Instance of" in java
- Avoiding instanceof in Java
- http://smsohan.com/blog/2011/11/01/using-instanceof-is-mostly-code-smell/
- http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism
- http://www.javapractices.com/topic/TopicAction.do?Id=31
- http://www.artima.com/interfacedesign/PreferPoly.html
所有这些中的建议往往是相同的:与其使用测试引用的类型并根据它切换到不同的行为,不如使用多态性:定义一个接口或 class您想要的操作的方法,并让您使用 instanceof
测试的对象实现他们自己的该方法版本以做正确的事情。
这条建议可以直接翻译成Haskell:
- 定义你自己的类型class来代表你想要的行为
- 为您感兴趣的每种类型实施此类型 class,并为每种类型实现正确的行为。
所以,你可以这样做:
class ToString a where
toString :: a -> String
instance ToString String where
toString str = str
instance ToString Integer where
toString i = show i
-- ...