我想创建一个函数,删除满足第二个参数中给定谓词的第一个元素。像这样:
removeFirst "abab" (< 'b') = "bab"
removeFirst "abab" (== 'b') = "aab"
removeFirst "abab" (> 'b') = "abab"
removeFirst [1,2,3,4] even = [1,3,4]
我想通过递归的方式做到这一点,并想出了这个:
removeFirst :: [a] -> (a -> Bool) -> [a]
removeFirst [] _ = []
rremoveFirst (x:xs) p = if p x then x : removeFirst xs p else removeFirst xs p
(灵感来自 this 问题) 但是我得到了一个类型错误,就像这样:
Couldn't match type ‘a’ with ‘Bool’
Expected: [Bool]
Actual: [a]
‘a’ is a rigid type variable bound by
the type signature for:
removeFirst :: forall a. [a] -> (a -> Bool) -> [a]
或者这个:
ghci> removeFirst [1,2,3,4] even
<interactive>:25:1: error:
* Variable not in scope: removeFirst :: [a0] -> (a1 -> Bool) -> t
* Perhaps you meant `rem' (imported from Prelude)
我知道这是一个相对简单的程序,我只是对 Haskell 还不够熟悉。我怎样才能做到这种“Haskell 风格”(一行)?
最佳答案
在“以风格”做之前,为什么不先简单地做,这样它就可以了。这就是我们学习的方式。
“Variable not in scope: removeFirst ...
”只是意味着您还没有定义名为 removeFirst
的函数。
所以看起来您首先尝试定义它(并且您显示的错误不与您显示的代码一致),然后您遇到了错误,因此它没有被定义,然后您尝试调用它并自然而然地收到错误消息说它尚未定义。
因此,将您的程序保存在源文件中,然后在 GHCi 中加载该文件。然后,如果您遇到任何错误,请将文件中的完整代码复制并粘贴到您的问题中(不要手动重新输入)。还请说明当您收到错误消息时您做了什么,准确地说。并确保通过复制粘贴来完整包含错误消息。
然后您的代码逻辑可以得到解决。
由于其他人已经发布了工作代码,以下是我将其编码为单行代码的方式:
remFirst :: [a] -> (a -> Bool) -> [a]
remFirst xs p = foldr g z xs xs
where
g x r ~(_:tl) -- "r" for recursive result
| p x -- we've found it, then
= tl -- just return the tail
| otherwise
= x : r tl -- keep x and continue
z _ = [] -- none were found
缩短了,就变成了
remFirst xs p =
foldr (\x r ~(_:tl) -> if p x then tl else x : r tl)
(const []) xs xs
https://stackoverflow.com/questions/69326029/