在 Haskell 上定义一个布尔函数,用于确定元素是否在列表中出现一次



所以我试图在Haskell中定义一个函数,如果给定一个整数和一个整数列表,无论整数只出现一次,都会给出"true"或"false"。

到目前为止,我已经得到了:

let once :: eq a => a ->

[a] -> Bool; once x l =

但是我还没有写完代码。我对Haskell很陌生,你可能知道。

首先使用模式匹配:

once x [] =
once x (y:ys) = 

这不会立即给你一个好的程序,但它会引导你朝着正确的方向前进。

这是一个不显式使用模式匹配的解决方案。相反,它会跟踪表示是否已找到事件的Bool

正如其他人指出的那样,这可能是一个家庭作业问题,所以我故意将thenelse分支留空。我鼓励user3482534尝试使用此代码并自行填写。

once :: Eq a => a -> [a] -> Bool
once a = foldr f False
    where f x b = if x == a then ??? else ???

编辑:我最初想到的天真实现是:

once :: Eq a => a -> [a] -> Bool
once a = foldr f False
    where f x b = if x == a then b /= True else b

但这是不正确的,

λ. once 'x' "xxx"
True

当然,这应该False,因为'x'发生不止一次。

但是,为了表明可以使用折叠来编写once,下面是一个修订版本,它使用自定义幺半群来跟踪元素出现的次数:

import Data.List
import Data.Foldable
import Data.Monoid
data Occur = Zero | Once | Many         
    deriving Eq
instance Monoid Occur where           
    mempty = Zero                      
    Zero `mappend` x    = x         
    x    `mappend` Zero = x      
    _    `mappend` _    = Many 
once :: Eq a => a -> [a] -> Bool
once a = (==) Once . foldMap f
    where f x = if x == a then Once else Zero
main = do                                
    let xss = inits "xxxxx"                        
    print $ map (once 'x') xss

哪些打印

[False,True,False,False,False]

不出所料。

once的结构与原始结构相似,但不完全相同。

我会像家庭作业问题一样回答这个问题,因为它看起来像一个。

阅读有关函数声明中的模式匹配的信息,尤其是当它们给出处理列表的示例时。 您稍后将使用 Data.List 中的工具,但您的教授可能正在教授模式匹配。

考虑一个将值映射到 1 或 0 的函数,具体取决于是否存在匹配项......

match :: a -> [a] -> [Int]
match x xs = map -- fill in the thing here such that
-- match 3 [1,2,3,4,5] == [0,0,1,0,0]

请注意,有一个 sum 函数,它接受数字列表并返回列表中数字的总和。因此,要计算匹配项,函数可以采用match函数并返回计数。

countN :: a -> [a] -> Int
countN x xs = ? $ match x xs

最后是一个利用countN函数来检查计数仅为 1 的函数。 (==1) .

希望你能弄清楚其余的...

您可以筛选列表,然后检查结果列表的长度。如果长度 == 1,则给定整数只出现一次:

once :: Eq a => a -> [a] -> Bool
once x = (== 1) . length . filter (== x)

用于一般计数,用import Data.List (foldl'),无点

count pred  =  foldl' ( n x -> if pred x then n + 1 else n) 0

适用如

count (< 10) [1 .. 10]  ==  9
count (== 'l') "Hello"  ==  2

once pred xs  =  count pred xs == 1

高效的O(n)短路谓词形式,测试谓词是否恰好满足一次:

once :: (a -> Bool) -> [a] -> Bool
once pred list = one list 0
   where
      one []       1             = True
      one []       _             = False
      one _        2             = False
      one (x : xs) n | pred x    = one xs (n + 1)
                     | otherwise = one xs n

或者,使用 any

none pred  =  not . any pred
once :: (a -> Bool) -> [a] -> Bool
once _    []                   = False
once pred (x : xs) | pred x    = none pred xs
                   | otherwise = one pred xs

elemOnce y  =  once (== y)

elemOnce 47 [1,1,2]  ==  False
elemOnce 2 [1,1,2]  ==  True
elemOnce 81 [81,81,2]  ==  False

最新更新