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

在Haskell上定义一个布尔函数,用于确定元素在列表中是否出现一次,haskell,Haskell,因此,我试图在Haskell中定义一个函数,如果给定一个整数和一系列整数,无论该整数是否只出现一次,都会给出“true”或“false” 到目前为止,我已经: let one::Eq a=>a->[a]->Bool;一次x l= 但是我还没有完成代码的编写。正如您可能知道的,我对Haskell非常陌生。从使用模式匹配开始: once x [] = once x (y:ys) = 这不会立即为您提供一个好的程序,但会引导您走向正确的方向。从使用模式匹配开始: once x [] = once

因此,我试图在Haskell中定义一个函数,如果给定一个整数和一系列整数,无论该整数是否只出现一次,都会给出“true”或“false”

到目前为止,我已经:

let one::Eq a=>a->[a]->Bool;一次x l=


但是我还没有完成代码的编写。正如您可能知道的,我对Haskell非常陌生。

从使用模式匹配开始:

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

这不会立即为您提供一个好的程序,但会引导您走向正确的方向。

从使用模式匹配开始:

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

这不会立即给你一个好的计划,但它会引导你走向正确的方向。

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


阅读函数声明中的模式匹配,特别是当它们给出处理列表的示例时。您将使用稍后提供的工具,但可能您的教授正在教授模式匹配。

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


阅读函数声明中的模式匹配,特别是当它们给出处理列表的示例时。您将使用稍后的工具,但您的教授可能正在教授模式匹配。

这里有一个解决方案,它不明确使用模式匹配。相反,它会跟踪表示是否已发现事件的
Bool

正如其他人所指出的,这可能是一个家庭作业问题,因此我故意将
然后
其他
分支留空。我鼓励用户3482534尝试使用这段代码并自己填充它们

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'
发生了不止一次

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

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
的结构与原来的类似,但不完全相同。

这里有一个解决方案,它没有明确使用模式匹配。相反,它会跟踪表示是否已发现事件的
Bool

正如其他人所指出的,这可能是一个家庭作业问题,因此我故意将
然后
其他
分支留空。我鼓励用户3482534尝试使用这段代码并自己填充它们

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'
发生了不止一次

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

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
的结构与原始的结构相似,但不完全相同。

考虑一个函数,该函数根据是否存在匹配将值映射到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或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)


希望您能找出其余的…

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

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

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

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

对于一般计数,使用
导入数据.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

高效的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
或者,使用
任何

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
给予

哪个


对于一般计数,使用
导入数据.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

高效的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
或者,使用
任何

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
给予

哪个


解决更一般的问题通常也更容易。我建议OP定义
发生次数::Eq a=>Int->a->[a]->Bool
?@TomEllis在这种情况下,我甚至建议OP定义一个函数
发生次数::Eq a=>a->[a]->[a]
,它可以找到列表中元素的每个实例,然后确定它发生了多少次就很简单了。@TomEllis,在这种情况下,这似乎是矫枉过正。有一个标准的Prelude函数可以填充我给出的定义,但OP也可以编写它。@bheklir:当然,甚至
count::a->[a]->Int
!解决更一般的问题通常也更容易。我建议OP定义
发生次数::Eq a=>Int->a->[a]->Bool
?@TomEllis对于这种情况,我甚至建议OP定义一个函数
发生次数