从 Haskell 中函数作为字段的数据类型导出 Eq 时出现问题

Jav*_*tro 3 methods haskell functional-programming equality deriving

我试图从数据类型中派生 Eq,并将函数作为字段,但无法按预期工作。

\n

我也尝试编写 te 实例但仍然不起作用

\n
data Conf = Conf {\n    rule :: ([Char] -> Char),\n    start :: Int,\n    numLines :: Double,\n    window :: Int,\n    move :: Int,\n    actualLine :: Int,\n    lastLine :: String\n} deriving (Eq)\n
Run Code Online (Sandbox Code Playgroud)\n

这是一个以图形方式打印钨金字塔的项目,例如,规则如下:

\n
rule30 :: [Char] -> Char\nrule30 "***" = ' '\nrule30 "** " = ' '\nrule30 "* *" = ' '\nrule30 "*  " = '*'\nrule30 " **" = '*'\nrule30 " * " = '*'\nrule30 "  *" = '*'\nrule30 "   " = ' '\nrule30 _     = ' '\n
Run Code Online (Sandbox Code Playgroud)\n

有很多规则需要遵循,正是因为这个原因,我想将“函数指针”直接保存在 Conf 数据类型中。

\n

那么,为什么我需要 deriving(Eq)?\n我需要它,因为主要是我检查是否为 Nothing (错误处理检查,例如,如果用户设置了错误的规则......)

\n

错误消息:

\n
src/Wolf.hs:24:13: error:\n\xe2\x80\xa2 No instance for (Eq ([Char] -> Char))\n    arising from the first field of \xe2\x80\x98Conf\xe2\x80\x99 (type \xe2\x80\x98[Char] -> Char\xe2\x80\x99)\n    (maybe you haven't applied a function to enough arguments?)\n  Possible fix:\n    use a standalone 'deriving instance' declaration,\n      so you can specify the instance context yourself\n\xe2\x80\xa2 When deriving the instance for (Eq Conf)\n   |\n24 | } deriving (Eq)\n   |             ^^\n
Run Code Online (Sandbox Code Playgroud)\n

我错过了什么?x

\n

lef*_*out 5

是什么让您认为这应该是可能的?如果您的类型包含函数字段,则比较您的类型的值是否相等至少与比较函数是否相等一样困难。但是要检查两个函数是否相等(在 Haskell 中,唯一合理的含义是外延相等),您需要检查它们是否在所有可能的输入上都一致。这是一件完全不可行的事情,即使对于简单的Int输入也是如此,但如果参数的类型是肯定的[Char]

那么,为什么我需要deriving(Eq)?我需要它,因为在main我检查是否是Nothing

你完全不需要那个Eq!通过使用来测试某个Maybe值是否有效是无效的,即使对于那些可能的类型也是如此。您应该使用模式匹配Nothing==

main = do
   ...
   let myConfq = ... :: Maybe Conf
   case myConfq of
     Nothing -> error "Meh, couldn't have conf"
     Just conf -> ...
Run Code Online (Sandbox Code Playgroud)

...或使用更高级别的组合器,可能基于MaybesApplicativeTraversable实例

import Data.Traversable

main = do
   ...
   let myConfq = ... :: Maybe Conf
   traverse ... myConfq
Run Code Online (Sandbox Code Playgroud)

  • @RobinZigmond 很公平,是的,“(== Nothing)”本身就足够快了。问题只是,这不会做任何事情来让您访问“Just”情况下包含的值,而这很可能也是必需的。— 真正低效的是类似的检查“length l == 0”列表是否为空。同样,将其更改为“l == []”将避免不必要的遍历整个事物,但这仍然可能不是正确的方法。 (2认同)