Preamble
You should pick up a tutorial or five on Haskell. Learning a language via stackoverflow questions is going to be slow and frustrating.
Comments
Type Signature and Type Variables
nonzero :: [int] -> Int
This is a type signature saying that nonzero
is a function from a list of int
to an value of type Int
.
int
with a lower-case i
is a type variable and means the function works over lists of values of any type what-so-ever.
You probably wanted nonzero :: [Int] -> Int
Function declarations
nonzero let counter = 0
Nonzero is a function and should be declared as <function> <args...> = <expression>
. So that would be:
nonzero xs = ...
Function body and immutability
The body of nonzero
is an expression of type Int
. In Haskell the variables are immutable. Saying counter = counter + 1
makes no more sense than it would in first grade math - your mental reaction should be "nuh-uh!". Instead think recursively in terms of base case and inductive step:
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
Progression
There are many different ways to write this function that get more or less fancy, more or less concise. Whenever you write a recursive function you're probably writing a form of fold or map over a list or other structure. Instead of manually looping over something there are lots of built-in functions to do this for you.
For example, determine if a value is a zero and emit a 1 if so or a 0 if not then sum the results:
nonzero xs = sum (map oneForZero xs)
oneForZero 0 = 1
oneForZero _anyOtherValue = 0
Notice the sum
function is one of these "folds" over the list of Ints that is specifically performing addition. We could do this manually instead:
nonzero xs = foldr accumulate 0 xs
accumulate 0 acc = acc + 1
accumulate _ acc = acc + 0