以这种方式考虑代码重用是一种很好的做法,我会谈到这一点,但首先:
使用函数组合写得更整洁
我可以先指出,我会oddOf
更简单地使用现有函数来定义您的函数:
oddOf :: Eq a -> a -> [a] -> Bool
oddOf value list = odd . length . filter (== value) $ list
f $ x = f x
但优先级较低,所以这是一种更简洁的写作方式(not . even . length . filter (== value) ) list
。
这是通过组合函数来工作的;我们获取列表并对其进行过滤,以便我们仅使用'operator section' 形式的value
部分应用来获得等于 的列表。接下来我们找到那个,检查它是否是,然后最后用 否定答案。这暗示了一种简洁的写作方式:(==)
(== value) :: Eq a => a -> Bool
length
even
not
evenOf
evenOf :: Eq a -> a -> [a] -> Bool
evenOf value list = even . length . filter (== value) $ list
事实上,由于前奏定义odd
为,因此从not . even
它开始evenOf
和定义会稍微简单oddOf
一些。
为什么not . oddOf
不是你想要的
查看类型,您有
not :: Bool -> Bool
oddOf :: Eq a => a -> [a] -> Bool
(.) :: (b -> bb) -> (a -> b) -> a -> bb -- function composition
现在->
关联到右边,这意味着真的,
oddOf :: Eq a => a -> ([a] -> Bool)
秘密地,这意味着 Haskell 函数只接受一个参数!(我们所认为的接受多个参数的函数实际上是接受一个参数然后返回一个将接受另一个参数的函数的函数,等等......)不幸的是,这意味着我们不能(.)
直接匹配类型,因为我们需要b
,Bool
不是[a] -> Bool
。
解决您的问题的简单方法
好的,抱歉我花了一段时间才得到你想要的答案,但我认为这一切都值得一说。
简单的解决方案 1是使用函数组合编写evenOf
,正如我在上面向您展示的那样。
oddOf value list = odd . length . filter (== value) $ list
evenOf value list = even . length . filter (== value) $ list
简单的解决方案 2通过提供所有参数evenOf
直接写入:oddOf
evenOf value list = not $ oddOf value list
oddOf value list = odd . length . filter (== value) $ list
简单的解决方案 3是evenOf value
通过not
与oddOf value
唯一的问题not.oddOf
是它oddOf
不Bool
直接返回 a ,而是返回 a [a]->Bool
。我们可以通过提供其中一个参数来解决这个问题。注意oddOf value
has 类型Eq a => [a] -> Bool
,所以我们可以用 组合它not
,因为它确实返回 a Bool
:
evenOf value = not . oddOf value
oddOf value list = odd . length . filter (== value) $ list
简单的解决方案 4将简单的解决方案 1 和 2 放在一起来编写,而不是oddOf
使用evenOf
:
oddOf value list = not $ evenOf value list
evenOf value list = even . length . filter (== value) $ list
(当然,您可以对简单的解决方案 1 和 3 做同样的事情。)
令人敬畏的改变大脑的方法来解决问题
每个 Haskell 程序员都应该阅读 Conal Elliott 出色的语义编辑器组合器网页/文章。
特别是,您应该阅读它,因为它以非常笼统的方式回答了您的问题标题“在不考虑实现细节的情况下定义与其他功能相关的功能”;“语义编辑器组合器”正是 Conal 对这个概念的表述。
主要思想是,您可以在编写函数后通过在括号中写入要更改的值的路径,要在该点应用的函数,然后是原始函数来编辑函数。在这种情况下,您需要将原始函数( )的结果( )应用于not
结果()。::Bool
::Eq a => [a]->Bool
:: Eq a => a -> [a] -> Bool
因此,如果您想使用 编辑结果的结果not
,请执行以下操作:
oddOf = (result.result) not evenOf
evenOf value list = even . length . filter (== value) $ list
Conal Elliott 定义result = (.)
是因为它在概念上更容易,但您可以定义
oddOf = ((.).(.)) not evenOf
evenOf value list = even . length . filter (== value) $ list
如果您愿意,可以直接使用。
如果你需要改变more :: a -> b -> [a] -> [b] -> Bool
,你可以使用
less = (result.result.result.result) not more
或者
less = ((.).(.).(.).(.)) not more
使用相同的想法,您可以在列表中更改,一对的一部分,一个论点,...
阅读论文以获得更深入和更全面的解释。