elem
命令允许我们执行以下操作:
elem 1 [1,2,3] = True
elem (Just 4) [(Just 5)] = False
我的问题是这是否可以在数学运算符上实现。
例如:
elem (+) [(+), (-), div]
根据elem :: (Eq a, Foldable t) => a -> t a -> Bool
的定义似乎不可能,而(+)
的定义为Num a => a -> a -> a
。
那怎么可以测试呢?
答案 0 :(得分:2)
是的,universe
包提供了对有限域上所有函数的相等性检查-价格。
Data.Universe.Instances.Reverse Data.Word> elem (+) [(+), (-), (*) :: Word8 -> Word8 -> Word8]
True
Data.Universe.Instances.Reverse Data.Word> elem (+) [(-), (*) :: Word8 -> Word8 -> Word8]
False
什么价格?比较是通过将功能应用于所有可能的输入并比较相应的输出来完成的。对于Word8
,只有大约60k的输入,因此在眨眼之前可以这样做,但是不要在Int -> Int -> Int
上尝试第一个输入...
答案 1 :(得分:2)
通常,功能相等为a big can of worms that you don't want to open。但是,对于数字运算符,实际上很常见的是遵循符号操作传统,即不将函数视为值映射,而是将其视为代数表达式,并且可以有效地比较那些 天真但并非完全不合理的方式。这需要合适的符号“反射类型”; simple-reflect在这里:您可以
{-# LANGUAGE FlexibleInstances #-}
import Debug.SimpleReflect
instance Eq (Expr -> Expr -> Expr) where
j == k = j magicL magicR == k magicL magicR
where magicL = 6837629875629876529923867
magicR = 9825763982763958726923876
main = print $ (+) `elem` [(+), (*), div :: Expr->Expr->Expr]
这仍然是一种启发式方法,可能会产生误报,但它确实适用于您的示例,也适用于涉及更多的示例。但是请注意,它不会以任何方式考虑算术定律,因此将给出(+) /= flip (+)
。
我建议尝试以不要求Haskell函数相等的方式来解决您的问题。