I feel like I need to give a parameter to idGetters type but it
doesn't need. Why? How should I call this?
You can't call it, because it's not a function. Its type is [Person->[Int]]
which is not a function but a list of functions.
In this case, because of its definition, it's in fact a list containing only one function - but you only know that from the implementation, not the type. If that's really the intended implementation then it would probably make more sense to just return that function not wrapped in a list, in which case the type would indeed be a function type Person->[Int]
. However, based on the other fields in your record I assume the definition will at some point be extended to include the 3 relevant getter functions: [parentList, childList, siblingList]
, and in this case you will of course need a list type.
ids p = (fmap ($ p)) idGetters
in this line how come can idGetters
return p's parentList which is [Int]?
I'm not quite sure I understand exactly what you're asking, but I accept that the definition can look a little confusing, so I'll try to explain it.
Firstly, the type of ids
is given as Person -> [[Int]]
, so it's a function that takes a Person
and returns a list of lists of Int
s. From this we can tell that the p
in the definition above - ids p = ...
- must be a Person
.
The result of that function call is the result of fmap
-ing a function over idGetters
. We'll worry about exactly what that function is shortly, but for now, just notice that idGetters
, as discussed above, is a list of functions each of which is of type Person -> [[Int]]
. So the function we fmap
over that must take as its argument a function, and this function argument will take a Person
as an argument and return a list of lists of Int
s.
That function, in the definition we are given, is ($ p)
, which is a section of the $ operator. That operator takes a function and a value and simply applies the function to the value, so when it's sectioned as ($ p)
, it's the function that takes another function and applies it to p
.
(It may be clearer to write this out as follows:
($ p) = \f -> ($ p) f
= \f -> f $ p
= \f -> f p
)
This hopefully now all fits together nicely. In the context of a function from the list idGetters
- which we know must be of type Person -> [Int]
- ($ p)
must take a Person
and apply that function to it, resulting in a list of Int
s. So we we fmap
that function over idGetters
, we get a list of lists of Int
s, which is what we know ids
must return (from its type signature).
With the very simply definition of idGetters
you have, consisting of the single function parentList
, all this will do is, given a Person
, output its parentList
(which is of type [Int]
) but wrapped inside another list (to have overall type [[Int]]
). If, as I suggested earlier, idGetters
was a list of the 3 relevant functions: [parentList, childList, siblingList]
, then ids
when applied to a Person
would return a list of 3 sublists, which are respectively the parentList
, childList
and siblingList
of that particular person. So it's actually a fairly straightforward function, just packaging up some of the information from a Person
's definition in some perhaps-relevant way.
I hope this clears up your questions - if not, please let me know in the comments.