我需要遍历整数列表,确定有多少个非零元素,然后返回这些元素。我不确定在遍历列表时是否应使用计数器变量,并且我对最有效的遍历列表本身的方式感兴趣。这是到目前为止我所拥有的...我是Haskell的新手,所以我正在用伪代码编写其中的一些代码。
nonzero :: [int] -> Int
nonzero let counter = 0
if xs == 0 counter = counter + 1
答案 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]
main=print$countNonzeroes[0..9]
howMany=(length.).filter
main=print$howMany(/=0)[0..9]