我需要遍历整数列表并确定有多少非零元素并返回这些元素。我不确定在迭代列表时是否应该使用计数器变量,我对迭代列表本身的最有效方法感兴趣。这是我到目前为止所拥有的...我是Haskell的新手,所以我正在用伪代码编写其中的一些内容。
nonzero :: [int] -> Int
nonzero let counter = 0
if xs == 0 counter = counter + 1
前言
你应该在Haskell上学习一五个教程。 通过堆栈溢出问题学习语言将是缓慢而令人沮丧的。
评论
类型签名和类型变量
nonzero :: [int] -> Int
这是一个类型签名,表示nonzero
是从int
列表到类型Int
值的函数。
- 带有小写
i
int
是一个类型变量,这意味着该函数适用于任何类型的值列表。
你可能想要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]
在线试用!