Eq 和 Ord 实例不一致?

2023-11-24

我有一个大型 Haskell 程序,它运行速度慢得令人沮丧。分析和测试表明,很大一部分时间都花在比较特定大型数据类型的相等性和顺序上,这非常重要。相等是一个有用的操作(这是状态空间搜索,图搜索比树搜索更可取),但我只需要此类的 Ord 实例即可使用 Maps。所以我想做的是说

instance Eq BigThing where
(==) b b' = name b == name b' &&
            firstPart b == firstPart b' &&
            secondPart b == secondPart b' &&
            {- ...and so on... -}

instance Ord BigThing where
compare b b' = compare (name b) (name b')

但由于不同对象的名称可能并不总是不同,因此这可能会出现奇怪的情况,即根据 == 两个 Big Things 可能不相等,但比较它们会产生 EQ。

这会导致 Haskell 库出现问题吗?有没有另一种方法可以满足详细的相等操作的要求,但又可以廉价排序?


首先,使用Text or ByteString代替String有帮助a lot不改变任何其他东西。

一般来说我不建议创建一个实例Eq不一致Ord。图书馆可以理所当然地依赖它,而且你永远不知道它会导致什么样的奇怪问题。 (例如,你是sure that Map不使用之间的关系Eq and Ord?)


如果您不需要Eq根本没有实例,你可以简单地定义

instance Eq BigThing where
    x == y  =  compare x y == EQ

那么平等就会与比较一致。不要求相等的值必须使所有字段都相等。


如果您需要一个Eq比较所有字段的实例,那么您可以通过包装来保持一致BigThing into a newtype,定义上面的Eq and Ord,并在您需要根据以下顺序进行排序时在您的算法中使用它name:

newtype BigThing' a b c = BigThing' (BigThing a b c)
instance Eq BigThing' where
    x == y  =  compare x y == EQ
instance Ord BigThing' where
    compare (BigThing b) (BigThing b') = compare (name b) (name b')

Update:既然您说任何排序都是可以接受的,那么您可以使用散列来发挥您的优势。为此,您可以使用hashable包裹。这个想法是,您在数据创建时预先计算哈希值,并在比较值时使用它们。如果两个值不同,几乎可以肯定它们的哈希值会不同,并且您只比较它们的哈希值(两个整数),仅此而已。它可能看起来像这样:

module BigThing
    ( BigThing()
    , bigThing
    , btHash, btName, btSurname
    )
where

import Data.Hashable

data BigThing = BigThing { btHash :: Int,
                           btName :: String,
                           btSurname :: String } -- etc
  deriving (Eq, Ord)
-- Since the derived Eq/Ord instances compare fields lexicographically and
-- btHash is the first, they'll compare the hash first and continue with the
-- other fields only if the hashes are equal.
-- See http://www.haskell.org/onlinereport/derived.html#sect10.1
--
-- Alternativelly, you can create similar Eq/Ord instances yourself, if for any
-- reason you don't want the hash to be the first field.

-- A smart constructor for creating instances. Your module will not export the
-- BigThing constructor, it will export this function instead:
bigThing :: String -> String -> BigThing
bigThing nm snm = BigThing (hash (nm, snm)) nm snm

请注意,使用此解决方案时,排序看起来是随机的,与字段没有明显的关系。

您还可以将此解决方案与之前的解决方案结合起来。或者,您可以创建一个小模块,用于使用其预先计算的哈希来包装任何类型(包装的值必须具有Eq与他们一致的实例Hashable实例)。

module HashOrd
    ( Hashed()
    , getHashed
    , hashedHash
    )
where

import Data.Hashable

data Hashed a = Hashed { hashedHash :: Int, getHashed :: a }
  deriving (Ord, Eq, Show, Read, Bounded)

hashed :: (Hashable a) => a -> Hashed a
hashed x = Hashed (hash x) x

instance Hashable a => Hashable (Hashed a) where
    hashWithSalt salt (Hashed _ x) = hashWithSalt salt x
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Eq 和 Ord 实例不一致? 的相关文章

  • Accelerate 和 Repa 是否有不同的用例?

    我一直在玩 Repa 和 Accelerate 它们都很有趣 但我不知道何时使用其中一个 何时使用另一个 他们是一起成长 是竞争对手 还是只是为了解决不同的问题 Repa 是一个用于高效数组构建和遍历的库 用 Haskell 编程并在 Ha
  • 使用通用元组函数一次进行多次折叠

    如何编写一个接受类型函数元组的函数ai gt b gt ai并返回一个函数 该函数接受类型元素的元组ai 类型的一个元素b 并将每个元素组合成一个新的元组ai 那是签名应该是这样的 f a1 gt b gt a1 a2 gt b gt a2
  • 函数式编程是否需要新的命名约定?

    我最近开始使用 Haskell 学习函数式编程 并在 Haskell 官方 wiki 上发现了这篇文章 如何阅读哈斯克尔 http www haskell org haskellwiki How to read Haskell What t
  • 用parsec解析递归数据

    import Data Attoparsec Text Lazy import Data Text Lazy Internal Text import Data Text Lazy pack data List a Nil Cons a L
  • 生成所有可能的树

    给定以下数据类型定义 data FormTree Empty Node FormTree FormTree deriving Show 我想编写一个函数 它生成一个无限列表 其中包含按长度排序的所有可能的树 例如节点数量 下面的代码几乎满足
  • 访问函数中的环境

    In main我可以读取我的配置文件 并将其提供为runReader somefunc myEnv正好 但somefunc不需要访问myEnv读者提供 链中的下一对也没有提供 需要 myEnv 中某些内容的函数是一个微小的叶函数 如何在不将
  • Haskell:找不到模块“Data.List.Split”

    我正在尝试在 Haskell 中拆分列表 据我所知 最简单的方法是splitOn 但是这个函数需要Data List Split 所以我尝试运行import Data List Split在前奏曲中 但是 我收到以下错误 Could not
  • 导入 Haskell 模块

    我是哈斯克尔的新手 为什么当我尝试使用时Days from Data Time我收到此错误 Could not find module Data Time It is a member of the hidden package time
  • 如何为强制长度为 2^n 的向量类型定义可用的 Applicative 实例

    对于某些应用程序 我需要长度为 2 n 的向量 为了强制某些操作的长度匹配 我使用 ist 应用实例定义了我的类型 如下所示 LANGUAGE GADTs DataKinds FlexibleInstances FlexibleContex
  • 在 Haskell 中计算移动平均线

    我正在学习 Haskell 所以我尝试实现移动平均函数 这是我的代码 mAverage Int gt Int gt Float mAverage x a fromIntegral k fromIntegral x k lt rawAvera
  • 为什么 Haskell 的默认字符串实现是一个字符链接列表?

    Haskell 默认值的事实String众所周知 实现在速度和内存方面都效率不高 据我所知 lists一般来说 在 Haskell 中实现为单链表 并且适用于大多数小型 简单数据类型 例如Int 这似乎不是一个好主意 但是对于String这
  • 将数据类型设置为 Kind * -> * 这不是函子

    布伦特 约尔吉类型分类百科全书 https www haskell org haskellwiki Typeclassopedia给出以下练习 举一个类型的例子 gt 不能将其制成 的实例Functor 不使用undefined 请告诉我什
  • Haskell 中的 print 是纯函数吗?

    Is print在 Haskell 中是纯函数 为什么或者为什么不 我认为不是 因为它并不总是返回与纯函数应返回的值相同的值 类型的值IO Int并不是真正的Int 它更像是一张纸 上面写着 嘿 Haskell 运行时 请生成一个Int如此
  • 在依赖类型的函数式编程语言中,扁平化列表是否更容易?

    在 haskell 中寻找一个可以展平任意深度嵌套列表的函数时 即应用的函数concat递归并在最后一次迭代时停止 使用非嵌套列表 我注意到这需要有一个更灵活的类型系统 因为随着列表深度的变化 输入类型也会变化 确实 有几个 stackov
  • 将两个 Int 值相除以获得 Float 的正确方法是什么?

    我想分两份IntHaskell 中的值并获得结果Float 我尝试这样做 foo Int gt Int gt Float foo a b fromRational a b 但 GHC 版本 6 12 1 告诉我 无法将预期类型 Intege
  • 对两种类型之间的二元关系进行建模

    有企业 也有人 用户可以对某个企业点赞或发表评论 但效果是一样的can not发生在一个人身上 当用户发布有关某个企业的内容或对其点赞时 该企业就被称为target喜欢或帖子 trait TargetingRelation Targetin
  • 在 Yesod 生态系统中,对某些文本进行 urlencode 的最佳方式是什么?

    我想对一些文本进行 url 编码 例如 用 20 替换每个空格等 我找到了 HTTP Network HTTP Base urlEncode 并且可以使用它 但我想知道是否还有其他通常在 Yesod 生态系统中使用的东西 不幸的是 由于 U
  • 在scala 2.13中,为什么有时无法显式调用类型类?

    这是 Shapeless 2 3 3 中的一个简单示例 val book author gt gt Benjamin Pierce title gt gt Types and Programming Languages id gt gt 2
  • Traversable 类型类的用途

    有人可以向我解释一下类型类的目的是什么吗Traversable 类型类定义是 class Functor t Foldable t gt Traversable t gt where So Traversable is a Functor
  • Haskell:IORef 的性能

    我一直在尝试在 Haskell 中编码一个需要使用大量可变引用的算法 但与纯粹的惰性代码相比 它 也许并不奇怪 非常慢 考虑一个非常简单的例子 module Main where import Data IORef import Contr

随机推荐

  • 在 eventArgs 中发送两个字符串的语法

    在下面的代码中 我需要知道引发事件时传递两个字符串的语法 PublishEvent Click public event EventHandler
  • 如何使用 python numpy.savetxt 将字符串和浮点数写入 ASCII 文件?

    我有一组包含字符串和浮点数的列表 例如 import numpy as num NAMES num array NAME 1 NAME 2 NAME 3 FLOATS num array 0 5 0 2 0 3 DAT num column
  • matplotlib:ValueError:无效的 PNG 标头

    import matplotlib pyplot as plt 我试图在同一文件夹中的许多其他 png 照片中读取一张 png 照片 有些照片使用以下行读取时没有错误 有些则返回 ValueError 无效的 PNG 标头 可能是什么原因
  • 如何使用SQL Order By语句对结果进行不区分大小写的排序?

    我有一个 SQLite 数据库 我试图按字母顺序排序 问题是 SQLite 在排序过程中似乎没有考虑 A a 因此我得到这样的结果 A 乙 C 时间 A 乙 C G 我想得到 A A 乙 乙 C C G 时间 有哪些我不知道的特殊 SQL
  • 如何防止

    在超过页面宽度时被剪裁?

    我正在使用 jQuery Mobile 但我的一个页面出现了问题 我有一个 p 嵌入到列表中 如下所示 p div div h1 Page 1 h1 div div ul li List Heading li li p A very lon
  • 在 Firestore 规则中声明函数

    这是我现在面临的 Firestore 安全规则问题 首先 这是我的 firestore 数据库中的数据结构示例 userProfiles userId userData companies companyId companyData 看起来
  • 如何从 Python 包内部读取(静态)文件?

    你能告诉我如何读取 Python 包中的文件吗 我的情况 我加载的包有许多我想从程序中加载的模板 用作字符串的文本文件 但如何指定此类文件的路径呢 想象一下我想从以下位置读取文件 package templates temp file 某种
  • 以编程方式升级应用程序权限 OS X

    我做了一些挖掘 我看到的主要想法是使用 setuid getuid 和使用授权服务 由于某种原因 它在编译时给我一个符号错误 但现在似乎已被弃用 我的应用程序需要能够在某个时刻请求根访问 用于访问原始磁盘驱动器 最好使用 OS X 身份验证
  • java.lang.IllegalArgumentException:已添加:Lorg/hamcrest/BaseDescription;转换为 Dalvik 格式失败,错误 1

    首先 至少有 2 个帖子有同样的问题 但这些解决方案不再起作用 至少在我的安装中不起作用 我将 m2e 与 Eclipse 和 Android 结合使用 并尝试通过选择 run as gt Android application 将应用程序
  • 按值对对象属性进行排序

    如果我有一个 JavaScript 对象 例如 var list you 100 me 75 foo 116 bar 15 有没有办法根据值对属性进行排序 所以我最终得到 list bar 15 me 75 you 100 foo 116
  • Akka (2.3.0) 无法加载 Slf4jEventHandler 类并出现 java.lang.ClassNotFoundException

    我从 Akka 2 2 3 迁移到 2 3 0 RC4 并在应用程序启动时收到此错误消息 error while starting up loggers akka ConfigurationException Logger specifie
  • 使用node.js提示用户输入? [复制]

    这个问题在这里已经有答案了 我正在开发一个使用 node js 运行的 JS 项目 但我不知道如何让提示正确地用于用户输入 我从 npm 安装了它 按照步骤操作 我可以让程序提示用户输入 但无法将结果存储在变量中 我想要的是提示用户每回合的
  • 如何从自定义的QMessageBox中捕获按钮点击?

    如何修改下面自定义 QMessageBox 的代码才能知道用户是否单击 是 或 否 from PySide import QtGui QtCore Create a somewhat regular QMessageBox msgBox Q
  • 没有为带有 ARC 的 MKMapView 释放内存

    我有一个习惯UIView called ActivityDetailView我实例化然后添加到父视图控制器内的滚动视图 当分配此自定义视图时 每次额外的内存都会占用大约 1mb 并且 Instruments 显示内存永远不会被释放 即使视图
  • 欧拉到矩阵以及矩阵到欧拉的转换

    我正在尝试使用 NET C 将欧拉角描述的 3D 旋转转换为矩阵 然后再转换回来 我的约定是 左手系统 x 向右 y 向上 z 向前 旋转顺序 绕 y 航向 绕 x 俯仰 绕 z 倾斜 使用左手定则旋转为正 拇指指向 无穷大 我的试用是 欧
  • Magento:覆盖客户帐户控制器

    您好 我正在尝试覆盖 Mage Customer AccountController 以便我可以扩展 createPostAction 方法 对于我的一生 我似乎无法做到这一点 它要么抛出一个 404 页面 这表明它不是文件的正确路径 要么
  • Java - 需要一个记录堆栈跟踪的日志包

    是否有一个记录器可以轻松记录我的堆栈跟踪 我得到的ex printStackTrace 我搜索了 log4j 文档但什么也没找到 关于记录堆栈跟踪 我可以自己做这个 StringWriter sw new StringWriter ex p
  • 如何防止exoplayer在向后搜索时重新加载?

    我正在使用 exoplayer 播放 mp3 曲目 都好 如果轨道完全缓冲 那么在向前查找的情况下 它不会按预期重新加载 但是 如果向后查找 它会重新加载 我该如何防止这种情况 是exo的bug吗 这并不是一个真正的解决方案 但您可以使用一
  • 如何获得第二个System.Thread.ThreadPool?

    如果我以嵌套方式使用 ThreadPool 我的应用程序将挂起 ThreadPool QueueUserWorkItem state gt ThreadPool QueueUserWorkItem Action 如何获得第二个独立的Thre
  • Eq 和 Ord 实例不一致?

    我有一个大型 Haskell 程序 它运行速度慢得令人沮丧 分析和测试表明 很大一部分时间都花在比较特定大型数据类型的相等性和顺序上 这非常重要 相等是一个有用的操作 这是状态空间搜索 图搜索比树搜索更可取 但我只需要此类的 Ord 实例即