3

是否可以从 Haskell 中的函数列表中删除重复项(如在 nub 中)?基本上,是否可以为 (Eq (Integer -> Integer)) 添加一个实例

在 ghci 中:

let fs = [(+2), (*2), (^2)]
let cs = concat $ map subsequences $ permutations fs
nub cs

<interactive>:31:1:
No instance for (Eq (Integer -> Integer))
  arising from a use of `nub'
Possible fix:
  add an instance declaration for (Eq (Integer -> Integer))
In the expression: nub cs
In an equation for `it': it = nub cs

提前致谢。

...

此外,根据 larsmans 的回答,我现在可以做到这一点

> let fs = [AddTwo, Double, Square]
> let css = nub $ concat $ map subsequences $ permutations fs

为了得到这个

> css

[[],[AddTwo],[Double],[AddTwo,Double],[Square],[AddTwo,Square],[Double,Square],[AddTwo,Double,Square],[Double,AddTwo],[Double,AddTwo,Square],[Square,Double],[Square,AddTwo],[Square,Double,AddTwo],[Double,Square,AddTwo],[Square,AddTwo,Double],[AddTwo,Square,Double]]

然后这个

> map (\cs-> call <$> cs <*> [3,4]) css

[[],[5,6],[6,8],[5,6,6,8],[9,16],[5,6,9,16],[6,8,9,16],[5,6,6,8,9,16],[6,8,5,6],[6,8,5,6,9,16],[9,16,6,8],[9,16,5,6],[9,16,6,8,5,6],[6,8,9,16,5,6],[9,16,5,6,6,8],[5,6,9,16,6,8]]

,这是我的初衷。

4

2 回答 2

8

不,这是不可能的。不能比较函数是否相等。

这样做的原因是:

  1. 指针比较对 Haskell 函数意义不大,因为之后 和 的相等性id\x -> id x根据后一种形式是否优化为id.
  2. 函数的扩展比较是不可能的,因为它需要对停止问题的积极解决方案(两个函数具有相同的停止行为是相等的必要条件)。

解决方法是将函数表示为数据:

data Function = AddTwo | Double | Square deriving Eq

call AddTwo  =  (+2)
call Double  =  (*2)
call Square  =  (^2)
于 2013-04-20T09:57:56.023 回答
3

不,不可能对Integer -> Integer函数执行此操作。

但是,如果您也可以使用更通用的类型签名Num a => a -> a如您的示例所示!一种天真的方式(不安全),会像

{-# LANGUAGE FlexibleInstances           #-}
{-# LANGUAGE NoMonomorphismRestriction   #-}

data NumResLog a = NRL { runNumRes :: a, runNumResLog :: String }
             deriving (Eq, Show)

instance (Num a) => Num (NumResLog a) where
  fromInteger n = NRL (fromInteger n) (show n)
  NRL a alog + NRL b blog
            = NRL (a+b) ( "("++alog++ ")+(" ++blog++")" )
  NRL a alog * NRL b blog
            = NRL (a*b) ( "("++alog++ ")*(" ++blog++")" )
  ...


instance (Num a) => Eq (NumResLog a -> NumResLog a) where
  f == g  = runNumResLog (f arg) == runNumResLog (g arg)
     where arg = NRL 0 "THE ARGUMENT"

unlogNumFn :: (NumResLog a -> NumResLog c) -> (a->c)
unlogNumFn f = runNumRes . f . (`NRL`"")

它基本上通过比较函数源代码的“规范化”版本来工作。当然,当您比较 eg 时(+1) == (1+),这会失败,它们在数字上是等效的,但 yield "(THE ARGUMENT)+(1)"vs."(1)+(THE ARGUMENT)"因此被指示为不相等。但是,由于函数Num a => a->a本质上被限制为多项式(是的,abssignum让它变得更加困难,但它仍然可行),您可以找到一种能够正确处理这些等价的数据类型。

这些东西可以这样使用:

> let fs = [(+2), (*2), (^2)]
> let cs = concat $ map subsequences $ permutations fs
> let ncs = map (map unlogNumFn) $ nub cs
> map (map ($ 1)) ncs
[[],[3],[2],[3,2],[1],[3,1],[2,1],[3,2,1],[2,3],[2,3,1],[1,2],[1,3],[1,2,3],[2,1,3],[1,3,2],[3,1,2]]
于 2013-04-20T10:11:11.380 回答