I'm learning Haskell and I found an interesting implementation of init
using foldr
. However, I have difficulty understanding how it works.
init' xs = foldr f (const []) xs id
where f x g h = h $ g (x:)
Consider I have an input of [1,2,3]
, then is would become
f 1 (f 2 ( f 3 (const []))) id
I substitute those parameters into f
and the innermost one becomes h $ (const []) (1:)
, which is simply h []
. However, when I want to reduce the expression further, I find it hard to grasp. The next one becomes f 2 (h [])
, which is
h $ (h []) (2:)
if it works like that. This looks confusing to me. To match the type of foldr
, h
should be of type [a] -> [a]
and h []
would just be of type [a]
, which isn't applicable to (2:)
.
I also thought about it in another way, that f x g
returns a function of type ([a] -> [a]) -> [a]
, this kinda makes sense considering applying id
afterwards. But then I realized I still don't know what this h
is doing here. It looks like h
conveys g (x:)
from last time into the next application.
Did I miss something when I think about doing fold
with function as accumulator?
I'd really appreciate if anyone could help me with this.
__init__ method It is called as a constructor in object oriented terminology. This method is called when an object is created from a class and it allows the class to initialize the attributes of the class.
The __init__ method is the Python equivalent of the C++ constructor in an object-oriented approach. The __init__ function is called every time an object is created from a class. The __init__ method lets the class initialize the object's attributes and serves no other purpose. It is only used within classes.
__init__ does act like a constructor. You'll need to pass "self" to any class functions as the first argument if you want them to behave as non-static methods. "self" are instance variables for your class. 'self' defines if a method is static or not!
What is __init__ in Python? The Default __init__ Constructor in C++ and Java. Constructors are used to initializing the object's state. The task of constructors is to initialize(assign values) to the data members of the class when an object of the class is created.
For a list [1,2,3]
, the init'
is substituted by:
init' [1,2,3]
= foldr f (const []) [1,2,3] id
= f 1 (foldr f (const []) [2,3]) id
Here f
is thus called with 1
as x
, foldr f (const []) [2,3]
as g
and id
h
, this thus means that the this is resolved to:
id (foldr f (const []) [2,3] (1:))
It thus means that instead of using id
in the recursion, we now will prepend 1:
to the result. Next we can resolve the inner foldr
to:
foldr f (const []) [2,3] (1:)
= f 2 (foldr f (const []) [3]) (1:)
= (1:) (foldr f (const []) [3] (2:))
The inner foldr
then results in:
foldr f (const []) [3] (2:)
= f 3 (foldr f (const []) []) (2:)
= (2:) (foldr f (const []) [] (3:))
finally the foldr f (const []) []
will resulve to const []
.
This thus means that:
foldr f (const []) [3] (2:)
= f 3 (foldr f (const []) []) (2:)
= (2:) (foldr f (const []) [] (3:))
= (2:) (const [] (3:))
The const
will thus ignore the argument (3:)
, and return an empty list. So the result of foldr f (const []) [3] (2:)
is [2]
:
foldr f (const []) [3] (2:)
= f 3 (foldr f (const []) []) (2:)
= (2:) (foldr f (const []) [] (3:))
= (2:) (const [] (3:))
= (2:) []
= [2]
If we substitute this in the foldr f (const []) [2,3] (1:)
, we get:
foldr f (const []) [2,3] (1:)
= f 2 (foldr f (const []) [3]) (1:)
= (1:) (foldr f (const []) [3] (2:))
= (1:) [2]
= [1,2]
so that means that init' [1,2,3]
will return [1,2]
.
This thus means that a
foldr f (const []) [x1, x2, …, xn] (x0:)
will be replaced by:
(x0:) (foldr f (const []) [x2, x3, …, xn] (x1:))
If the list gets exhausted, then it will replace:
foldr f (const []) [] (xn:)
with:
const [] (xn:)
so the last element will be ignored by the const
function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With