在哈斯克尔中计算列表中的非零元素



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

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

前言

你应该在Haskell上学习一五个教程。 通过堆栈溢出问题学习语言将是缓慢而令人沮丧的。

评论

类型签名和类型变量

nonzero :: [int] -> Int

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

  • 带有小写iint是一个类型变量,这意味着该函数适用于任何类型的值列表。

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

函数声明

nonzero let counter = 0

非零是一个函数,应声明为<function> <args...> = <expression>。 所以这将是:

nonzero xs = ...

函数体和不变性

nonzero的主体是Int类型的表达式。 在Haskell中,变量是不可变的。说counter = counter + 1并不比一年级数学更有意义——你的心理反应应该是"呃! 相反,从基本情况和归纳步骤的角度递归思考:

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

级数

有许多不同的方法来编写这个函数,这些方法或多或少变得花哨,或多或少简洁。 每当你写一个递归函数时,你可能在列表或其他结构上写一种折叠映射的形式。 与其手动循环某些内容,不如使用许多内置函数为您执行此操作。

例如,确定某个值是否为零,如果是,则发出 1,如果不是,则发出 0,则对结果求和:

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

请注意,sum函数是专门执行加法的 Int 列表上的这些"折叠"之一。 我们可以手动执行此操作:

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

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

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

在线试用!

howMany=(length.(。滤波器

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

在线试用!

最新更新