gpt4 book ai didi

haskell - 如何 "newtype"IntSet?

转载 作者:行者123 更新时间:2023-12-02 14:11:56 24 4
gpt4 key购买 nike

感谢 newtypeGeneralizedNewtypeDeriving 扩展,人们可以轻松定义不同的轻量级类型:

newtype PersonId = PersonId Int deriving (Eq, Ord, Show, NFData, ...)
newtype GroupId = GroupId Int deriving (Eq, Ord, Show, NFData, ...)

它允许类型系统确保 PersonId 不会在需要 GroupId 的情况下意外使用,但仍然从 Int 继承选定的类型类实例.

现在可以简单地将 PersonIdSetGroupIdSet 定义为

import Data.Set (Set)
import qualified Data.Set as Set

type PersonIdSet = Set PersonId
type GroupIdSet = Set GroupId

noGroups :: GroupIdSet
noGroups = Set.empty

-- should not type-check
foo = PersonId 123 `Set.member` noGroups

-- should type-check
bar = GroupId 123 `Set.member` noGroups

这是类型安全的,因为映射是由键类型参数化的,而且 Set.member 操作是多态的,所以我不需要定义每个 id 类型的变体,例如作为 personIdSetMembergroupIdSetMember (以及我可能想要使用的所有其他设置操作)

...但是我如何以与示例类似的方式分别使用更高效的 IntSet 来代替 PersonIdSetGroupIdSet多于?有没有一种简单的方法,无需将整个 Data.IntSet API 包装/复制为类型类?

最佳答案

我认为你必须按照你所说的包装IntSet。但是,您可以引入幻像类型来创建一系列彼此兼容的 IDIDSet:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import qualified Data.IntSet as IntSet
import Data.IntSet (IntSet)

newtype ID a = ID { unID :: Int }
deriving ( Eq, Ord, Show, Num )

newtype IDSet a = IDSet { unIDSet :: IntSet }
deriving ( Eq, Ord, Show )

null :: IDSet a -> Bool
null = IntSet.null . unIDSet

member :: ID a -> IDSet a -> Bool
member i = IntSet.member (unID i) . unIDSet

empty :: IDSet a
empty = IDSet $ IntSet.empty

singleton :: ID a -> IDSet a
singleton = IDSet . IntSet.singleton . unID

insert :: ID a -> IDSet a -> IDSet a
insert i = IDSet . IntSet.insert (unID i) . unIDSet

delete :: ID a -> IDSet a -> IDSet a
delete i = IDSet . IntSet.delete (unID i) . unIDSet

因此,假设您有一个 Person 类型和一个 Group 类型,您可以执行以下操作:

type PersonID = ID Person
type PersonIDSet = IDSet Person

type GroupID = ID Group
type GroupIDSet = IDSet Group

关于haskell - 如何 "newtype"IntSet?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5746590/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com