Haskell函数的比较

Haskell函数的比较,haskell,Haskell,有没有办法比较Haskell中的两个函数 我认为答案是否定的,因为函数不会派生Eq类型的类。然而,我正在尝试编写一个非常简单的函数,这似乎是一种正常的操作: search :: ((Enum a) => a -> a) -> Card -> [Card] search op x list = if (op == succ && rank x == King) || (op == pred &&

有没有办法比较Haskell中的两个函数

我认为答案是否定的,因为函数不会派生Eq类型的类。然而,我正在尝试编写一个非常简单的函数,这似乎是一种正常的操作:

search :: ((Enum a) => a -> a) -> Card -> [Card]
search op x list = if (op == succ && rank x == King) || 
                      (op == pred && rank x == Ace)
                   then []
                   else let c = [ n | n <- list, rank n == op (rank x)]
                     in if length c == 1
                     then x : search op (head c) list
                     else []
基本上,它要么向上或向下搜索卡片列表,寻找与x中下一张或上一张排名的卡片相匹配的卡片,构建一个列表。通过将“pred”或“succ”函数作为运算符,它可以向前和向后工作。但是,我需要检查它是否超出枚举的界限,否则它会引发异常

因此,我正在寻找一种方法来防止异常或解决此问题

任何关于改进代码的其他建议也将不胜感激:)

感谢所有的好建议,这就是我提出的解决方案(从每个答案中提取一些信息!):

编辑:下面是正确的解决方案:

 maybeSucc x | x == maxBound = Nothing
             | otherwise = Just (succ x)
 maybePred x | x == minBound = Nothing  
             | otherwise = Just (pred x)

-- takes a list of cards which have a rank one op than x
-- only if there is exactly one is it sequential, otherwise end matching
search :: (Rank -> Maybe Rank) -> Rank -> [Card] -> [Card]
search op x list = case filter (\n -> Just (rank n) == op x) list of
                    [y] -> y : search op (rank y) list
                     _ -> []
测试:

1) 您的
op
过于笼统。您只能将其用于卡的任何类型
rank(undefined::Card)
,所以只需将其设置为
RankThing->RankThing
。此外,函数类型签名缺少返回值类型

2) 示例预期用途看起来是
搜索成功xs
,但这相当笨拙,两个处理边界的辅助函数如何:

searchUp King _ = []
searchUp x ys = search succ x ys

searchDown Ace _ = []
searchDown x ys = search pred x ys
这对您的用户来说可能更容易理解,并且避免了检查操作的需要

3) 如果您确实想检查执行的操作,并且知道该操作将是两种可能性之一,那么您可以命名该操作或使用已知答案测试(KAT)对其进行测试。例如:

data Operation = Succ | Pred

search :: Operation -> Card -> [Card] -> []
search Succ King _ = []
search Succ x ys = search' succ x ys
search Pred Ace _ = []
search Pred x ys = search' pred x ys
以及KAT解决方案(国际海事组织认为相当蹩脚):


下面的代码可能无法编译,但希望您能理解:

data Op = Succ | Pred deriving Eq

fromOp :: Enum a => Op -> a -> a
fromOp Succ = succ
fromOp Pred = pred

search :: Op -> Card -> [Card] -> [Card]
search op x list = if (op == Succ && rank x == King) || 
                      (op == Pred && rank x == Ace)
                   then []
                   else let c = [ n | n <- list, rank n == (fromOp op) (rank x)]
                     in if length c == 1
                     then x : search op (head c) list
                     else []
data Op=such | Pred推导公式
fromOp::Enum a=>Op->a->a
fromOp Succ=Succ
fromOp Pred=Pred
搜索::Op->Card->[Card]->[Card]
搜索op x list=if(op==such&&rank x==King)|
(op==Pred&&rank x==Ace)
然后[]

否则,让c=[n | n好吧,在Haskell中没有“引用相等”的概念,在一般情况下,函数的“行为相等”是不可能检查的。尽管对于只在小的有限类型上运行的函数(如
Rank
可能会这样做),这通常是不明智的,因为如果你不小心,它会导致组合爆炸

您可以通过多种方式实现当前目标,例如:

  • 不要直接使用
    succ
    pred
    ,而是使用类型为
    Enum a=>a->的自保护函数,可能是一个
    的函数,该函数不产生任何异常而产生任何异常

  • 传入一个“停止”值以进行检查,例如
    search op end x list=if x==end then[]..

  • 完全忘记
    succ
    pred
    ,只需传入要比较的值列表,例如
    搜索::[Rank]->Card->[Card]->[Card]
    ,如果列组列表为空,则结束搜索

关于您的代码的其他几点意见:

  • 您对列表的理解正在重塑方向盘——寻找标准的库函数,如
    过滤器
    ,它们可以满足您的需求

  • 不要将列表的
    长度
    与一个小常量进行比较,而是使用模式匹配

无用的回答
没有,也永远不会有一种方法来比较两个函数是否相等。有一个数学证明,这在一般情况下是不可能的

“实用”方法要么取决于编译器的内部工作(例如,如果两个函数在内部由相同的内存地址表示,则两个函数相等),要么不如预期的有用。 succ==(+1)的预期结果是什么?让a==1在succ==(+a)中如何

我想不出一种定义(=)函数的方法总是有意义的,我相信其他人也不能

与问题无关的事情 类型签名缺少返回类型

您的函数有一个rank 2类型,它不是标准的Haskell 98,更重要的是,在这种情况下不需要。您不关心传入的函数是否可以处理任何枚举类型,您只关心它对rank有效:

search :: (Rank -> Rank) -> Card -> [Card] -> [Card]   -- much simpler.
我会尝试更频繁地使用case,如果/那么更少地使用。特别是,我会写:

case [ n | n <- list, rank n == op (rank x)] of
    [y] -> x : search op y list   -- length == 1
    _ -> []                       -- otherwise
或者,您可以使参数更通用,并传递一个可能会正常失败的函数(不返回任何内容):

maybeSucc x | x==maxBound=Nothing
|否则=仅(成功x)
搜索::(排名->可能排名)->卡片->[卡片]->[卡片]
搜索op x列表=案例op(排名x)
没有->[]

只要函数在适当的域和范围内(Enum、Bounded、Eq等,域和范围的组合稍有不同),就可以直接比较有限的函数,甚至是高阶函数,然后使用类型类自动化处理

我在Haskell邮件列表的一个帖子中写下了这个想法,然后(更恰当地说)在一个FDPE会议(维多利亚,BC)上发表了一篇文章。我以前从未见过这样的想法,但如果其他人也这么做,我也不会感到惊讶:这是一个非常简单的想法,一旦你克服了这个问题“函数不能为相等进行比较”。当然,关于偏袒性和严格性的常见警告也适用:例如,对于两个函数,如果它们都因某个公共参数而无法终止,则不能返回True

但是对于有限域来说,这种技术是有效的,并且提供了很多实际用途(另外,使用起来真的很有趣:)

编辑:我将代码添加到;它可以在Hugs中工作,但需要对GHC进行一些调整

编辑2:我在hpaste-d代码中添加了一个pragma和注释,这样它就可以工作了
data Op = Succ | Pred deriving Eq

fromOp :: Enum a => Op -> a -> a
fromOp Succ = succ
fromOp Pred = pred

search :: Op -> Card -> [Card] -> [Card]
search op x list = if (op == Succ && rank x == King) || 
                      (op == Pred && rank x == Ace)
                   then []
                   else let c = [ n | n <- list, rank n == (fromOp op) (rank x)]
                     in if length c == 1
                     then x : search op (head c) list
                     else []
search :: (Rank -> Rank) -> Card -> [Card] -> [Card]   -- much simpler.
case [ n | n <- list, rank n == op (rank x)] of
    [y] -> x : search op y list   -- length == 1
    _ -> []                       -- otherwise
data Direction = Succ | Pred deriving(Eq)

search :: Direction -> Card -> [Card] -> [Card]
search dir x list = if (dir == Succ && rank x == King) ...
    ... let op = case Direction of Succ -> succ ; Pred -> pred
        in ...
maybeSucc x | x == maxBound = Nothing
            | otherwise = Just (succ x)

search :: (Rank -> Maybe Rank) -> Card -> [Card] -> [Card]
search op x list = case op (rank x) of
    Nothing -> []
    Just theRank -> case [ n | n <- list, rank n == theRank ] of ...
(\x -> [(&&x), (||x), not]) == (\y -> [(y&&), (y||), not . not . not])