Haskell Length function implementation - haskell

I am learning Haskell programming, and I am trying to understand how lists work, hence I attempted writing two possible length functions:
myLength :: [a] -> Integer
myLength = foldr (\x -> (+) 1) 0
myLength1 :: [a] -> Integer
myLength1 [] = 0
myLength1 (x:xs) = (+1) (myLength1 xs)
Which one is better?
From my point of view, myLength1 is much easier to understand, and looks natural for operating on lists.
On the other hand, myLength is shorter and it does not use recursion; does this imply myLength runs faster than myLength1?

Take in mind this "pseudo implementation" of foldr:
foldr :: function -> initializer -> [a] -> b
foldr _ i [] = i
foldr f i (x:xs) = x `f` (foldr f i xs)
Now we have your code
myLength :: [a] -> Integer
myLength = foldr (\x -> (+) 1) 0
myLength1 :: [a] -> Integer
myLength1 [] = 0
myLength1 (x:xs) = (+1) (myLength1 xs)
Since foldr is also recursive itself, your myLength1 and myLength will be almost the same but in the first case the recursive call is done by foldr instead of explicitly by yourself. They should run around the same time.

Both functions do the same thing : foldr use recursion and will end up executing similarly to your directly recursive function. It could be argued that the foldr version is cleaner (once you're accustomed to them, higher order function are often more readable than direct recursion).
But those two functions are pretty bad : they'll both end up building a big thunk (an unevaluated value) 1 + (1 + (1 + ... + 0)..)) which will take a lot of memory ( O(n) space ) and will slow evaluation. To avoid that you should start adding the 1s from the beginning of the list, like so :
betterLength xs = go 0 xs
where
go n [] = n
go n (_:xs) = n `seq` go (n+1) xs
The seq ensures that n is evaluated before the go function is called recursively and thus there is no accumulation of +1. With the BangPatterns extension, you can write this :
betterLength xs = go 0 xs
where
go n [] = n
go !n (_:xs) = go (n+1) xs
It is also possible to do this version with a fold :
betterLength = foldl' (\n _ -> n + 1) 0
where the foldl' start from the left and is strict (').

Using foldr, it can be implemented as:
length' xs = foldr (\_ n -> 1 + n) 0 xs
Explanation:
The lambda function (\_ x -> n + 1) will increment the accumulator by one every time there is an element. For instance:
lenght' [1..4]
will be applied as:
1 + ( 1 + ( 1 + ( 1 + 0)))
Recall that foldr is defined like this:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f v [] = v
foldr f v (x:xs) = f x (foldr f v xs)

Related

Is there any terminating fold in Haskell?

I need some kind of fold which can terminate if I already have the data I want.
For example I need to find first 3 numbers which are greater than 5. I decided to use Either for termination and my code looks like this:
terminatingFold :: ([b] -> a -> Either [b] [b]) -> [a] -> [b]
terminatingFold f l = reverse $ either id id $ fold [] l
where fold acc [] = Right acc
fold acc (x:xs) = f acc x >>= flip fold xs
first3NumsGreater5 acc x =
if length acc >= 3
then Left acc
else Right (if x > 5 then (x : acc) else acc)
Are there some more clever/generic approaches?
The result of your function is a list, and it would be desirable if it were produced lazily, that is, extracting one item from the result should only require evaluating the input list up until the item is found there.
Unfolds are under-appreciated for these kinds of tasks. Instead of focusing on "consuming" the input list, let's think of it as a seed from which (paired with some internal accumulator) we can produce the result, element by element.
Let's define a Seed type that contains a generic accumulator paired with the as-yet unconsumed parts of the input:
{-# LANGUAGE NamedFieldPuns #-}
import Data.List (unfoldr)
data Seed acc input = Seed {acc :: acc, pending :: [input]}
Now let's reformulate first3NumsGreater5 as a function that either produces the next output element from the Seed, of signals that there aren't any more elements:
type Counter = Int
first3NumsGreater5 :: Seed Counter Int -> Maybe (Int, Seed Counter Int)
first3NumsGreater5 (Seed {acc, pending})
| acc >= 3 =
Nothing
| otherwise =
case dropWhile (<= 5) pending of
[] -> Nothing
x : xs -> Just (x, Seed {acc = succ acc, pending = xs})
Now our main function can be written in terms of unfoldr:
unfoldFromList ::
(Seed acc input -> Maybe (output, Seed acc input)) ->
acc ->
[input] ->
[output]
unfoldFromList next acc pending = unfoldr next (Seed {acc, pending})
Putting it to work:
main :: IO ()
main = print $ unfoldFromList first3NumsGreater5 0 [0, 6, 2, 7, 9, 10, 11]
-- [6,7,9]
Normally an early termination-capable fold is foldr with the combining function which is non-strict in its second argument. But, its information flow is right-to-left (if any), while you want it left-to-right.
A possible solution is to make foldr function as a left fold, which can then be made to stop early:
foldlWhile :: Foldable t
=> (a -> Bool) -> (r -> a -> r) -> r
-> t a -> r
foldlWhile t f a xs = foldr cons (\acc -> acc) xs a
where
cons x r acc | t x = r (f acc x)
| otherwise = acc
You will need to tweak this for t to test the acc instead of x, to fit your purposes.
This function is foldlWhile from https://wiki.haskell.org/Foldl_as_foldr_alternative, re-written a little. foldl'Breaking from there might fit the bill a bit better.
foldr with the lazy reducer function can express corecursion perfectly fine just like unfoldr does.
And your code is already lazy: terminatingFold (\acc x -> Left acc) [1..] => []. That's why I'm not sure if this answer is "more clever", as you've requested.
edit: following a comment by #danidiaz, to make it properly lazy you'd have to code it as e.g.
first3above5 :: (Foldable t, Ord a, Num a)
=> t a -> [a]
first3above5 xs = foldr cons (const []) xs 0
where
cons x r i | x > 5 = if i==2 then [x]
else x : r (i+1)
| otherwise = r i
This can be generalized further by abstracting the test and the count.
Of course it's just reimplementing take 3 . filter (> 5), but shows how to do it in general with foldr.

Find the K'th element of a list using foldr

I try to implement own safe search element by index in list.
I think, that my function have to have this signature:
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
iteration = undefined
init_val = undefined
I have problem with implementation of iteration. I think, that it has to look like this:
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
where
iteration :: a -> (Int -> [a]) -> Int -> a
iteration x g 0 = []
iteration x g n = x (n - 1)
init_val :: Int -> a
init_val = const 0
But It has to many errors. My intuition about haskell is wrong.
you have
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
if null xs holds, foldr iteration init_val [] => init_val, so
init_val n
must make sense. Nothing to return, so
= Nothing
is all we can do here, to fit the return type.
So init_val is a function, :: Int -> Maybe a. By the definition of foldr, this is also what the "recursive" argument to the combining function is, "coming from the right":
iteration x r
but then this call must also return just such a function itself (again, by the definition of foldr, foldr f z [a,b,c,...,n] == f a (f b (f c (...(f n z)...))), f :: a -> b -> b i.e. it must return a value of the same type as it gets in its 2nd argument ), so
n | n==0 = Just x
That was easy, 0-th element is the one at hand, x; what if n > 0?
| n>0 = ... (n-1)
Right? Just one more step left for you to do on your own... :) It's not x (the list's element) that goes on the dots there; it must be a function. We've already received such a function, as an argument...
To see what's going on here, it might help to check the case when the input is a one-element list, first,
safe_search [x] n = foldr iteration init_val [x] n
= iteration x init_val n
and with two elements,
[x1, x2] n = iteration x1 (iteration x2 init_val) n
-- iteration x r n
Hope it is clear now.
edit: So, this resembles the usual foldr-based implementation of zip fused with the descending enumeration from n down, indeed encoding the more higher-level definition of
foo xs n = ($ zip xs [n,n-1..]) $
dropWhile ((>0) . snd) >>>
map fst >>>
take 1 >>> listToMaybe
= drop n >>> take 1 >>> listToMaybe $ xs
Think about a few things.
What type should init_val have?
What do you need to do with g? g is the trickiest part of this code. If you've ever learned about continuation-passing style, you should probably think of both init_val and g as continuations.
What does x represent? What will you need to do with it?
I wrote up an explanation some time ago about how the definition of foldl in terms of foldr works. You may find it helpful.
I suggest to use standard foldr pattern, because it is easier to read and understand the code, when you use standard functions:
foldr has the type foldr :: (a -> b -> b) -> [a] -> b -> [b],
where third argument b is the accumulator acc for elements of your list [a].
You need to stop adding elements of your list [a] to acc after you've added desired element of your list. Then you take head of the resulting list [b] and thus get desired element of the list [a].
To get n'th element of the list xs, you need to add length xs - n elements of xs to the accumulator acc, counting from the end of the list.
But where to use an iterator if we want to use the standard foldr function to improve the readability of our code? We can use it in our accumulator, representing it as a tuple (acc, iterator). We subtract 1 from the iterator each turn we add element from our initial list xs to the acc and stop to add elements of xs to the acc when our iterator is equal 0.
Then we apply head . fst to the result of our foldr function to get the desired element of the initial list xs and wrap it with Just constructor.
Of course, if length - 1 of our initial list xs is less than the index of desired element n, the result of the whole function safeSearch will be Nothing.
Here is the code of the function safeSearch:
safeSearch :: Int -> [a] -> Maybe a
safeSearch n xs
| (length xs - 1) < n = Nothing
| otherwise = return $ findElem n' xs
where findElem num =
head .
fst .
foldr (\x (acc,iterator) ->
if iterator /= 0
then (x : acc,iterator - 1)
else (acc,iterator))
([],num)
n' = length xs - n

Accumulator in foldr

In the Haskell Wikibook, foldr is implemented as follows:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f acc [] = acc
foldr f acc (x:xs) = f x (foldr f acc xs)
It is stated that the initial value of the accumulator is set as an argument. But as I understand it, acc is the identity value for the operation (e.g. 0 for sum or 1 for product) and its value does not change during the execution of the function. Why then is it referred to here and in other texts as an accumulator, implying that it changes or accumulates a value step by step?
I can see that an accumulator is relevant in a left fold, such as foldl, but is the wikibook explanation incorrect, and only for symmetry, in which case it is wrong?
Consider the evaluation of a simple foldr expression based on the (correct) definition you provided:
foldr (+) 0 [1,2,3,4]
= 1 + foldr (+) 0 [2,3,4]
= 1 + 2 + foldr (+) 0 [3,4]
= 1 + 2 + 3 + foldr (+) 0 [4]
= 1 + 2 + 3 + 4 + foldr (+) 0 []
= 1 + 2 + 3 + 4 + 0
= 10
So you are right: acc doesn't really "accumulate" anything. It never takes on a value other than 0.
Why is it called "acc" if it isn't an accumulator? Similarity to foldl? Hysterical raisins? A lie to children? I'm not sure.
Edit: I'll also point out that the GHC implementation of foldr uses z (presumably for zero) rather than acc.
acc doesn't really accumulate anything in the case of foldr as has been pointed out.
I'd add that without it, it's not clear what should happen when the input is an empty list.
It also changes the type signature of f, limiting the functions that can be used.
E.g:
foldr' :: (a -> a -> a) -> [a] -> a
foldr' f [] = error "empty list???"
foldr' f (x:[]) = x
foldr' f (x:xs) = f x (foldr' f xs)

Double every other element of list from right in Haskell

I have a list and I want to double every other element in this list from the right.
There is another related question that solves this problem but it doubles from the left, not the right: Haskell: Double every 2nd element in list
For example, in my scenario, [1,2,3,4] would become [2,2,6,4], and in that question, [1,2,3,4] would become [1,4,3,8].
How would I implement this?
I think that the top answer misinterpreted the question. The title clearly states that the OP wants to double the second, fourth, etc. elements from the right of the list. Ørjan Johansen's answer is correct, but slow. Here is my more efficient solution:
doubleFromRight :: [Integer] -> [Integer]
doubleFromRight xs = fst $ foldr (\x (acc, bool) ->
((if bool then 2 * x else x) : acc,
not bool)) ([], False) xs
It folds over the list from the right. The initial value is a tuple containing the empty list and a boolean. The boolean starts as false and flips every time. The value is multiplied by 2 only if the boolean is true.
OK, as #TomEllis mentions, everyone else seems to have interpreted your question as about odd-numbered elements from the left, instead of as even-numbered from the right, as your title implies.
Since you start checking positions from the right, there is no way to know what to double until the end of the list has been found. So the solution cannot be lazy, and will need to temporarily store the entire list somewhere (even if just on the execution stack) before returning anything.
Given this, the simplest solution might be to just apply reverse before and after the from-left solution:
doubleFromRight = reverse . doubleFromLeft . reverse
Think about it.
double = zipWith ($) (cycle [(*2),id])
EDIT I should note, this isn't really my solution it is the solution of the linked post with the (*2) and id flipped. That's why I said think about it because it was such a trivial fix.
A direct implementation would be:
doubleOddElements :: [Int] -> [Int]
doubleOddElements [] = []
doubleOddElements [x] = [2 * x]
doubleOddElements (x:y:xs) = (2*x):y:(doubleOddElements xs)
Okay, so not elegant or efficient like the other answers, but I wrote this from a beginners standpoint (I am one) in terms of readability and basic functionality.
This doubles every second number, beginning from the right.
Using this script: doubleEveryOther [1,3,6,9,12,15,18] produces [1,6,6,18,12,30,18] and doubleEveryOther [1,3,6,9,12,15] produces [2,3,12,9,24,15]
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[]) = [x]
doubleEveryOther (x:y:zs)
| (length (x:y:zs)) `mod` 2 /= 0 = x : y*2 : doubleEveryOther zs
| otherwise = x*2 : y : doubleEveryOther zs
Trying to generalize the problem a bit: Since we want to double every 2nd element from the end, we can't know in advance if it'll be every odd or even from the start. So the easiest way is to construct both, count if the overall size is even or odd, and then decide.
Let's define an Applicative data structure that captures:
Having two variants of values,
keeping the parity of the length (odd/even), and
alternating the two when two such values are combined,
as follows:
import Control.Applicative
import Data.Monoid
import qualified Data.Traversable as T
data Switching m = Switching !Bool m m
deriving (Eq, Ord, Show)
instance Functor Switching where
fmap f (Switching b x y) = Switching b (f x) (f y)
instance Applicative Switching where
pure x = Switching False x x
(Switching False f g) <*> (Switching b2 x y) = Switching b2 (f x) (g y)
(Switching True f g) <*> (Switching b2 x y) = Switching (not b2) (f y) (g x)
So traversing a list will yield two lists looking like this:
x1 y2 x3 y4 ...
y1 x2 y3 x4 ...
two zig-zag-ing copies. Now we can compute
double2 :: (Num m) => m -> Switching m
double2 x = Switching True (2 * x) x
double2ndRight :: (Num m, T.Traversable f) => f m -> f m
double2ndRight k = case T.traverse double2 k of
Switching True _ y -> y
Switching False x _ -> x
Here are mine two solutions, note that I'm complete beginner in Haskell.
First one uses list functions, head, tail and lenght:
doubleSecondFromEnd :: [Integer] -> [Integer]
doubleSecondFromEnd [] = [] -- Do nothing on empty list
doubleSecondFromEnd n
| length n `mod` 2 == 0 = head n * 2 : doubleSecondFromEnd (tail n)
| otherwise = head n : doubleSecondFromEnd (tail n)
Second one, similar but with a different approach only uses length function:
doubleSecondFromEnd2 :: [Integer] -> [Integer]
doubleSecondFromEnd2 [] = [] -- Do nothing on empty list
doubleSecondFromEnd2 (x:y)
| length y `mod` 2 /= 0 = x * 2 : doubleSecondFromEnd2 y
| otherwise = x : doubleSecondFromEnd2 y
I am just learning Haskell so please find the following beginner solution. I try to use limited cool functions like zipWith , cycle, or reverse
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther s#(x:xs)
| (length s) `mod` 2 == 0 = (x * 2) : (doubleEveryOther xs)
| otherwise = x : (doubleEveryOther xs)
The key thing to note that when doubling every element from the right you can put the doubling into two cases:
If the list is even length, you will ultimately end up doubling the first element of the list.
If the list is odd length, you will not be doubling the first element of the list.
I answered this as part of the homework assignment from CS194
My first thought was:
doubleOdd (x:xs) = (2*x):(doubleEven xs)
doubleOdd [] = []
doubleEven (x:xs) = x:(doubleOdd xs)
doubleEven [] = []
DiegoNolan's solution is more elegant, in that the function and sequence length are more easily altered, but it took me a moment to grok.
Adding the requirement to operate from the right makes it a little more complex. foldr is a neat starting point for doing something from the right, so let me try:
doubleOddFromRight = third . foldr builder (id,double,[])
where third (_,_,x) = x
builder x (fx,fy,xs) = (fy, fx, fx x : xs)
double x = 2 * x
This swaps the two functions fx and fy for each entry. To find the value of any entry will require a traversal to the end of the list, finding whether the length was odd or even.
This is my answer to this CIS 194 homework assignment. It's implemented using just the stuff that was introduced in lecture 1 + reverse.
doubleEveryOtherLeftToRight :: [Integer] -> [Integer]
doubleEveryOtherLeftToRight [] = []
doubleEveryOtherLeftToRight (x:[]) = [x]
doubleEveryOtherLeftToRight (x:y:zs) = x:y*2:(doubleEveryOtherLeftToRight zs)
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther xs = reverse (doubleEveryOtherLeftToRight (reverse xs))
How about this for simplicity?
doubleEveryOtherRev :: [Integer] -> [Integer]
doubleEveryOtherRev l = doubleRev (reverse l) []
where
doubleRev [] a = a
doubleRev (x:[]) a = (x:a)
doubleRev (x:y:zs) a = doubleRev zs (2*y:x:a)
You would have to feed a reversed list of digits, in case you followed that course's recommendation, because it will double every other element as it reverses again. I think that this is different than using twice the reverse function, with another to double every other digit in between, because you won't need to know the full extent of their list by the second time. In other words, it solves that course's problem, but someone correct me if I'm wrong.
We can also do it like this:
doubleEveryOther = reverse . zipWith (*) value . reverse
where
value = 1 : 2 : value
Some answers seems not deal with odd/even length of list.
doubleEveryOtherEvenList = zipWith ($) (cycle [(*2),id])
doubleEveryOther :: [Int] -> [Int]
doubleEveryOther n
| length n `mod` 2 == 0 = doubleEveryOtherEvenList n
| otherwise = (head n) : doubleEveryOtherEvenList (tail n)
Taking an edx course in haskell, this is my noob solution.
doubleSecondR :: [Integer] -> [Integer]
doubleSecondR xs = reverse(zipWith (*) (reverse xs) ys)
where ys = repeat' [1,2]
repeat' :: [a] -> [a]
repeat' xs = xs ++ repeat' xs
I'm too coming to this question from the CIS 194 course.
I did this two ways. First I figured that the point of the question should only rely on functions or ways of programming mentioned in either of the 3 possible sources listed. The course lecture 1, Real World Haskell ch. 1,2 and Learn You a Haskell ch. 2.
So OK:
Recursion, conditionals
reverse, basic functions like max, min, odd, even
list functions e.g. head, tail, ...
Not OK:
foldr, foldl, map
Higher Order functions
Anything beyond these
First solution, just using recursion with a counter:
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther xs = loopDoubles xs 1
loopDoubles :: [Integer] -> Integer -> [Integer]
loopDoubles [] _ = []
loopDoubles xs n = loopDoubles (init xs) (n + 1) ++ [doubleEven (last xs) n]
doubleEven :: Integer -> Integer -> Integer
doubleEven x n = if even n then x * 2 else x
This method uses recursion, but avoids calculating the length at each level of the recursion.
Second method breaking the aforemention rules of mine:
doubleEveryOther' :: [Integer] -> [Integer]
doubleEveryOther' xs = map (\x -> if even (fst x) then (snd x) * 2 else snd x) $ zip (reverse [1..n]) xs
where n = length(xs)
This second one works by building up a reversed set of indexes and then mapping over these. This does calculate the length but only once.
e.g. [1,1,1,1] -> [(4,1),(3,1),(2,1),(1,1)]
Both of these are following the requirement of doubling every other element from the right.
> doubleEveryOther [1,2,3,4]
[2,2,6,4]
> doubleEveryOther [1,2,3]
[1,4,3]
> doubleEveryOther' [1,2,3,4]
[2,2,6,4]
> doubleEveryOther' [1,2,3]
[1,4,3]
I'm guessing the OP posed this question while researching an answer to the Homework 1 assignment from Haskell CIS194 Course. Very little Haskell has been imparted to the student at that stage of the course, so while the above answers are correct, they're beyond the comprehension of the learning student because elements such as lambdas, function composition (.), and even library routines like length and reverse haven't been introduced yet. Here is an answer that matches the stage of teaching in the course:
doubleEveryOtherEven :: [Integer] -> [Integer]
doubleEveryOtherEven [] = []
doubleEveryOtherEven (x:y:xs) = x*2 : y : doubleEveryOtherEven xs
doubleEveryOtherOdd :: [Integer] -> [Integer]
doubleEveryOtherOdd (x:[]) = [x]
doubleEveryOtherOdd (x:y:xs) = x : y*2 : doubleEveryOtherOdd xs
integerListLen :: [Integer] -> Integer
integerListLen [] = 0
integerListLen (x:xs) = 1 + integerListLen xs
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther xs
| integerListLen xs `mod` 2 == 0 = doubleEveryOtherEven xs -- also handles empty list case
| otherwise = doubleEveryOtherOdd xs
The calculation requires foreknowledge on whether the list has an even or odd number of elements, to determine which digit in each pair of digits should be doubled. However, basic Haskell pattern-matching only permits matching list elements from left-to-right (example: x:xs), which means you can't determine if there are an odd or even number of elements until you've reached the end of the list, but by then it's too late since you need to do calculations on each left-hand pair of elements while working through the list to reach the end.
The solution is to split the doubling logic into two functions - one which handles even-length lists and another which handles odd-length lists. A third function is needed to determine which of those two functions to call for a given list, which in turn needs an additional function that can calculate the length of the list so we can establish whether the list has an odd or even number of elements (again, since the length library function hasn't been introduced at this stage of the course).
This solution is also in keeping with the advisory in the Week 1 lesson, which states: "It’s good Haskell style to build up more complex functions by combining many simple ones."
Here is my answer for CIS 194 homework1.
I took idea from toDigits and toDigitsRev. It's not fancy, but works.
takeLastTwo :: [Int] -> [Int]
takeLastTwo [] = []
takeLastTwo (x : y : []) = [x, y]
takeLastTwo (x : xs) = takeLastTwo xs
removeLastTwo :: [Int] -> [Int]
removeLastTwo [] = []
removeLastTwo (x : y : []) = []
removeLastTwo (x : xs) = x : removeLastTwo xs
doubleEveryOther :: [Int] -> [Int]
doubleEveryOther [] = []
doubleEveryOther (x : []) = [x]
doubleEveryOther (x : y : []) = (2 * x) : y : []
doubleEveryOther xs = doubleEveryOther (removeLastTwo xs) ++ doubleEveryOther (takeLastTwo xs)

strict evaluation of integer accumulator

Here is a classic first attempt at a custom length function:
length1 [] = 0
length1 (x:xs) = 1 + length1 xs
And here is a tail-recursive version:
length2 = length2' 0 where
length2' n [] = n
length2' n (x:xs) = length2' (n+1) xs
However, (n+1) will not be evaluted strictly, but instad Haskell will create a thunk, right?
Is this a correct way to prevent the creation of the thunk, thus forcing strict evaluation of (n+1)?
length3 = length3' 0 where
length3' n [] = n
length3' n (x:xs) = length3' (n+1) $! xs
How would I achieve the same effect with seq instead of $!?
The usual way now to write it would be as:
length3 :: [a] -> Int
length3 = go 0
where
go :: Int -> [a] -> Int
go n [] = n
go n (x:xs) = n `seq` go (n+1) xs
Namely, as a fold over the list strict in the accumulator.
GHC yields the direct translation to Core:
Main.$wgo :: forall a_abz. GHC.Prim.Int# -> [a_abz] -> GHC.Prim.Int#
Main.$wgo =
\ (n :: GHC.Prim.Int#) (xs :: [a_abz]) ->
case xs of
[] -> n
_ : xs -> Main.$wgo a (GHC.Prim.+# n 1) xs
Showing that it is unboxed (and thus strict) in the accumulator.
I don't think that's quite right--$! is strict in its second argument, so you're just forcing the list and not the accumulator.
You can get the right strictness using seq something like this:
let n' = n + 1 in n' `seq` length3' n' xs
I think a more readable version would use bang patterns (a GHC extension):
length3' !n (x:xs) = ...

Resources