提问人:Javier Sánchez Castro 提问时间:3/10/2022 最后编辑:Javier Sánchez Castro 更新时间:3/11/2022 访问量:208
在Haskell中使用函数作为字段从数据类型派生Eq时出现的问题
Problem when deriving Eq from data type with function as field in Haskell
问:
我正在尝试使用函数作为字段从数据类型派生 Eq,但没有按预期工作。
我也尝试编写te实例,但仍然不起作用
data Conf = Conf {
rule :: ([Char] -> Char),
start :: Int,
numLines :: Double,
window :: Int,
move :: Int,
actualLine :: Int,
lastLine :: String
} deriving (Eq)
这是一个以印刷图形形式包含 wolfram 金字塔的项目,例如,规则是:
rule30 :: [Char] -> Char
rule30 "***" = ' '
rule30 "** " = ' '
rule30 "* *" = ' '
rule30 "* " = '*'
rule30 " **" = '*'
rule30 " * " = '*'
rule30 " *" = '*'
rule30 " " = ' '
rule30 _ = ' '
有很多规则要遵循,正是出于这个原因,我想直接将“函数指针”保存在 Conf 数据类型中。
那么,为什么我需要导数(方程)? 我需要它,因为在主要情况下,我检查是否为“无”(错误处理检查,例如,如果用户设置了错误的规则......
错误消息:
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)
| ^^
我错过了什么?
答:
是什么让你认为这是可能的?如果您的类型包含函数字段,则比较您的类型的值是否相等至少与比较函数是否相等一样困难。但是要检查两个函数是否相等(在 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 -> ...
...或者使用更高级别的组合器,可能基于 s 或实例Maybe
Applicative
Traversable
import Data.Traversable
main = do
...
let myConfq = ... :: Maybe Conf
traverse ... myConfq
评论
a
Eq
== Nothing
Maybe a
Eq
a
(== Nothing)
Just
length l == 0
l == []
我正在考虑允许注释数据类型字段的想法,这些字段将允许你想要的东西: 通过字段:派生中更精细的粒度
这个想法是定义一个比较总是成功的 newtype:
newtype Ignore a = Ignore a
instance Eq (Ignore a) where
_ == _ = True
instance Ord (Ignore a) where
compare _ _ = EQ
然后只注释函数字段;然后,当我们派生数据类型的实例时,操作字段的实例实际上是通过 newtype (==) @(via Ignore)
执行的:(==) @([Char] -> Char)
data Conf = Conf
{ rule :: [Char] -> Char
via Ignore ([Char] -> Char)
, start :: Int
, ..
}
deriving
stock (Eq, Ord)
评论
Eq
评论