【问题标题】:Alias for datatypes in HaskellHaskell 中数据类型的别名
【发布时间】:2013-02-14 09:26:35
【问题描述】:

所以我有这样的结构:

data Maybe a = Nothing | Just a  

但我想要一个定义为

的结构
data MaybeInt = Nothing | Just Int

有没有办法使用Maybe a 定义MaybeInt,如果可以,如何定义?

【问题讨论】:

  • type MaybeInt = Maybe Int 是你的意思吗?
  • type,是的,但不要这样做,当同义词真正意味着什么时使用同义词——MaybeInt 绝对不会比Maybe Int 给你买任何东西。
  • @DanielFath 什么样的类型接口? Haskell 应该接受 Maybe Int 在任何地方接受 MaybeInt
  • @DanielFath:那么您只需拥有convert :: Maybe Int -> Int
  • @DanielFath 请注意,Maybe -> Int 不是有效的类型签名。不管你用类型同义词写MaybeInt -> Int 还是Maybe Int -> Int 都没有区别。

标签: haskell types


【解决方案1】:

有几种方法可以定义MaybeInt。我会陈述他们然后有一些评论。

直接

data MaybeInt = NothingInt | JustInt Int

新类型

newtype MaybeInt = MI (Maybe Int)

键入同义词

type MaybeInt = Maybe Int

普通

-- just use `(Maybe Int)` wherever you would write `MaybeInt`

评论

最常见的是使用 plain 方法,因为大多数人都熟悉Maybe,因此知道使用JustNothing 来匹配它。这使它对图书馆有好处——非常透明。 type synonym 方法是一种常见的文档方法,但对于您的同义词基本上没用。它使foo :: Int -> Maybe Intbar :: Int -> MaybeInt 具有相同的类型签名。这也意味着只要有人知道MaybeInt === Maybe Int,他们就可以使用Just/Nothing 构造函数进行匹配。

newtype 方法变得相当有趣。每次您想使用MaybeInt 类型 时,您都必须在这里开始“包装”和“展开”MI 构造函数。比较:

baz :: MaybeInt -> Bool
baz (MI Nothing) = False
baz (MI (Just int)) = True

这很好,因为如果您不导出 MI,那么没有人将能够匹配MaybeInt(尽管对其中发生的事情有很好的猜测)。这对于制作稳定的 API 非常有用。 newtype 的另一个有趣的特性是您可以为 MaybeInt 编写新的 instances,这与 Maybe 的内置 Maybe 不同。例如,您可以覆盖 Monoid 实例

instance Monoid MaybeInt where
  mempty = MI Nothing
  mi `mappend` (MI Nothing) = mi
  _  `mappend` mi           = mi

这与 Data.Monoid 内置的 Last a newtype 相同,它包装了 Maybe as。

最后,我们得到了完整的data 实例。它更冗长、更容易出错、速度稍慢(因为编译器必须跟踪新的、唯一的数据类型),并且需要人们学习新的构造函数。对于与Maybe Int 明显相同的功能,根本没有理由使用它。

【讨论】:

  • +1,但 Monoid 实例看起来很可疑。 MI (Just x) <> mempty 应该是 MI (Just x)。不过,这可行:x `mappend` (MI Nothing) = x; _ `mappend` y = y
  • 哦,是的,完全错误!这是一个有效的Monoid 实例......只是一种可怕的实例。现已修复。
猜你喜欢
  • 2012-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-08
  • 2018-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多