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

发布于 01-13 06:26 字数 1125 浏览 3 评论 0原文

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

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

data Conf = Conf {
    rule :: ([Char] -> Char),
    start :: Int,
    numLines :: Double,
    window :: Int,
    move :: Int,
    actualLine :: Int,
    lastLine :: String
} deriving (Eq)

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

rule30 :: [Char] -> Char
rule30 "***" = ' '
rule30 "** " = ' '
rule30 "* *" = ' '
rule30 "*  " = '*'
rule30 " **" = '*'
rule30 " * " = '*'
rule30 "  *" = '*'
rule30 "   " = ' '
rule30 _     = ' '

有很多规则要遵循,因此我想保存直接在 Conf 数据类型中的“函数指针”。

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

错误消息:

src/Wolf.hs:24:13: error:
• No instance for (Eq ([Char] -> Char))
    arising from the first field of ‘Conf’ (type ‘[Char] -> Char’)
    (maybe you haven't applied a function to enough arguments?)
  Possible fix:
    use a standalone 'deriving instance' declaration,
      so you can specify the instance context yourself
• When deriving the instance for (Eq Conf)
   |
24 | } deriving (Eq)
   |             ^^

我缺少什么?x

I'm trying to deriving Eq from data type with a function as a field but doesn't work as expected.

I also try to write te instance but still doesn't work

data Conf = Conf {
    rule :: ([Char] -> Char),
    start :: Int,
    numLines :: Double,
    window :: Int,
    move :: Int,
    actualLine :: Int,
    lastLine :: String
} deriving (Eq)

It's a project that consist in print graphicaly the wolfram pyramids, for instance, the rules are for example:

rule30 :: [Char] -> Char
rule30 "***" = ' '
rule30 "** " = ' '
rule30 "* *" = ' '
rule30 "*  " = '*'
rule30 " **" = '*'
rule30 " * " = '*'
rule30 "  *" = '*'
rule30 "   " = ' '
rule30 _     = ' '

There are many rules to follow, it's for that reason that I want to save the "function pointer" directly in Conf data type.

So, why I need the deriving(Eq)?
I need it because in the main I check if is Nothing (error handling check, for example if the user puts a bad rule...)

Error Msg:

src/Wolf.hs:24:13: error:
• No instance for (Eq ([Char] -> Char))
    arising from the first field of ‘Conf’ (type ‘[Char] -> Char’)
    (maybe you haven't applied a function to enough arguments?)
  Possible fix:
    use a standalone 'deriving instance' declaration,
      so you can specify the instance context yourself
• When deriving the instance for (Eq Conf)
   |
24 | } deriving (Eq)
   |             ^^

What am I missing?x

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

森林散布2025-01-20 06:26:20

是什么让您认为这应该是可能的?如果您的类型包含函数字段,则比较您的类型的值是否相等至少与比较函数是否相等一样困难。但要检查两个函数是否相等(在 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 -> ...

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

import Data.Traversable

main = do
   ...
   let myConfq = ... :: Maybe Conf
   traverse ... myConfq

What makes you think that this should be possible? If your type contains a function field, then comparing values of your type for equality is at least as difficult as comparing functions for equality. But to check that two functions are equal (in Haskell, the only sensible meaning is extensional equality), you'd need to check that they agree on all possible inputs. That's an utterly infeasible thing to do, even for simple Int inputs but certainly if the arguments have type [Char].

So, why I need the deriving(Eq)? I need it because in the main I check if is Nothing

You totally don't need Eq for that! Testing whether a Maybe value is Nothing by using == is ineffective, even on those types where it is possible. You should instead use either pattern matching

main = do
   ...
   let myConfq = ... :: Maybe Conf
   case myConfq of
     Nothing -> error "Meh, couldn't have conf"
     Just conf -> ...

...or use higher level combinators, perhaps based on Maybes Applicative or Traversable instances

import Data.Traversable

main = do
   ...
   let myConfq = ... :: Maybe Conf
   traverse ... myConfq
橘虞初梦2025-01-20 06:26:20

我正在考虑允许注释数据类型字段的想法,该数据类型将允许您想要的内容: 通过字段:派生的粒度更细

这个想法是定义一个新类型,其中比较总是成功:

newtype Ignore a = Ignore a

instance Eq (Ignore a) where
  _ == _ = True

instance Ord (Ignore a) where
  compare _ _ = EQ

然后仅注释函数字段;然后,当我们派生数据类型的实例时,操作字段 (==) @([Char] -> Char) 的实例实际上是通过 newtype (==) @(通过忽略)

data Conf = Conf
  { rule  :: [Char] -> Char
         via Ignore ([Char] -> Char)
  , start :: Int
  , ..
  }
  deriving
  stock (Eq, Ord)

I am thinking about ideas that would allow annotating fields of a datatype that would allow what you want: Via fields: finer granularity in deriving

The idea is to define a newtype where comparisons always succeed:

newtype Ignore a = Ignore a

instance Eq (Ignore a) where
  _ == _ = True

instance Ord (Ignore a) where
  compare _ _ = EQ

and then annotating only the function field; then when we derive instances of the datatype the instances that manipulate the field (==) @([Char] -> Char) are actually performed via the newtype (==) @(via Ignore):

data Conf = Conf
  { rule  :: [Char] -> Char
         via Ignore ([Char] -> Char)
  , start :: Int
  , ..
  }
  deriving
  stock (Eq, Ord)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文