【问题标题】:Haskell instanceof analogue?Haskell 类比实例?
【发布时间】:2015-05-30 20:11:49
【问题描述】:

我是 Haskell 的新手,所以我的问题可能很愚蠢。

我想要一个函数

show2 :: (Show a) => a -> String

对于任何a,它将返回show a,但如果a 本身是String,则返回a。 如何实现?

附:如果这个功能已经在某个地方实现了,那就太好了,但我还是想看一个实现的例子。

【问题讨论】:

  • 这通常是个坏主意,因为它的价值。
  • 顺便说一句,您可能已经知道这一点,但由于您是新手:=> 之前的部分称为上下文(在您的情况下为 Show a)。由于那里只有一个,因此您不必使用括号。
  • @LouisWasserman 你能解释一下,为什么?
  • @Hindsight 通常不建议在 Haskell 中执行任何类型的反射逻辑; “特定类型的例外”等不受欢迎。
  • @Hindsight why 不受欢迎的原因是 parametricity 已被发现是代码拥有的极其有价值的属性;这是一个想法,如果你的函数在某个类型变量中是多态的,那么它统一以相同的方式处理所有类型。这往往会使代码更加可重用、可组合且易于推理。

标签: haskell instanceof


【解决方案1】:

Haskell 的设计方式与instanceof 检查的概念非常相反。 Haskell 的设计没有包含这种运行时类型检查,因为 Haskell 非常注重强大的编译时保证:函数在运行时学习其参数的类型不应比它在编译时知道的更精确。

这并不意味着 Haskell 中不存在该功能——Lee 的回答演示了如何做到这一点——但在 Haskell 中,这是 库提供的 opt-in 功能,不是语言的核心部分(不像 Java 这样的语言,它是始终存在的核心特性——你不能选择退出它!)。

请注意,即使在面向对象编程中,instanceof 运算符也是有争议的。许多面向对象的程序员强烈反对使用它。几个例子(数百个):

所有这些中的建议往往是相同的:不要使用测试引用的类型并基于它切换到不同的行为,而是使用多态性:定义一个接口或类,该接口或类具有用于您想要的操作的方法,并让您使用 instanceof 测试的对象实现他们自己的该方法版本以执行正确的操作。

这个建议可以直接翻译成 Haskell:

  1. 定义您自己的类型类来表示您想要的行为
  2. 为您感兴趣的每种类型实现此类型类,并为每种类型提供正确的行为。

所以,你可以这样做:

class ToString a where
    toString :: a -> String

instance ToString String where
    toString str = str

instance ToString Integer where
    toString i = show i

-- ...

【讨论】:

  • 太棒了!我可以做类似instance Show a => ToString a 的事情吗?
【解决方案2】:

你可以用这段肮脏而危险的代码来做到这一点:

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"

【讨论】:

  • {-# LANGUAGE ... #-} 编译指示通常比-X 标志更好。
【解决方案3】:

你可以从Data.Typeable使用cast

show2 :: (Typeable a, Show a) => a -> String
show2 s = maybe (show s) id ms
  where ms = cast s :: Maybe String

【讨论】:

    猜你喜欢
    • 2016-08-12
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多