计算Haskell列表中的非零元素

时间:2020-01-29 23:49:49

标签: haskell

我需要遍历整数列表,确定有多少个非零元素,然后返回这些元素。我不确定在遍历列表时是否应使用计数器变量,并且我对最有效的遍历列表本身的方式感兴趣。这是到目前为止我所拥有的...我是Haskell的新手,所以我正在用伪代码编写其中的一些代码。

nonzero :: [int] -> Int
nonzero let counter = 0
if xs == 0 counter = counter + 1

2 个答案:

答案 0 :(得分:8)

序言

您应该在Haskell上选一本教程或五本。通过stackoverflow问题学习语言将变得缓慢而令人沮丧。

评论

类型签名和类型变量

nonzero :: [int] -> Int

这是一种类型签名,它表示nonzero是从int列表到类型Int的值的函数。

  • int(带有小写的i)是类型变量,表示该函数可以处理任何类型的值列表。

您可能想要nonzero :: [Int] -> Int

函数声明

nonzero let counter = 0

非零是一个函数,应声明为<function> <args...> = <expression>。这样就可以了:

nonzero xs = ...

功能主体和不变性

nonzero的主体是类型Int的表达式。在Haskell中,变量是不可变的。说counter = counter + 1并不比一年级数学更有意义-您的心理反应应该是“ nuh-uh!”。而是根据基本案例和归纳步骤进行递归思考:

case xs of
   [] ->  -- Base case, what is the desired value when
          -- the list is empty?  `counter=0` right!
          0 -- In other words, nonzero [] ~ 0
    x:rest -> -- Inductive case.
              -- What do we do with an element?
              -- Compare with zero and...
         if x == 0
            then 1 + nonzero rest -- Add one to the answer
            else nonzero rest     -- Or don't add one if not

进度

有许多不同的方式来编写此函数,它们或多或少地显得简朴。每当您编写递归函数时,您可能会在列表或其他结构上编写 fold map 的形式。有很多内置函数可以代替您手动进行循环操作。

例如,确定一个值是否为零,如果为零则发出1,否则为0,然后将结果求和:

nonzero xs = sum (map oneForZero xs)
oneForZero 0 = 1
oneForZero _anyOtherValue = 0

注意sum函数是专门执行加法的Ints列表上的这些“折叠”之一。我们可以手动执行以下操作:

nonzero xs = foldr accumulate 0 xs
accumulate 0 acc = acc + 1
accumulate _ acc = acc + 0

答案 1 :(得分:-2)

countNonzeroes xs = sum [1 | x <-xs,x / = 0]

countNonzeroes xs=sum[1|x<-xs,x/=0]
main=print$countNonzeroes[0..9]

Try it online!

howMany =(长度。)。过滤器

howMany=(length.).filter
main=print$howMany(/=0)[0..9]

Try it online!