1

I have a record of Person

data Person = Person
 {name :: Name
 ,lastname :: LastName
 ,personId :: Int
 ,parentList :: [Int]
 ,childList :: [Int]
 ,siblingList ::[Int]
 }
 deriving (Show,Typeable,Data,Eq) 

and get function

getPersonId::Person -> Int
getPersonId = personId --here why/how can I achieve to get personId field of Person record since I don't have any Person p

They work correctly and I get what I want but I struggle to understand these functions:

idGetters :: [Person->[Int]]
idGetters = [parentList]

ids :: Person -> [[Int]]
ids p = (fmap ($ p)) idGetters

I am studying for functors and applicative at the moment but I should be able to understand idGetters function(or whatever it is because by definition it is list of functions not a function itself)* with the help of what I know so far. What I couldn't understand is :

  1. I feel like I need to give a parameter to idGetters type but it doesn't need. Why? How should I call this?
  2. ids p = (fmap ($ p)) idGetters in this line how come can idGetters return p's parentList which is [Int]?
Mahmut Salman
  • 111
  • 1
  • 10

1 Answers1

4

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 Ints. 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 Ints.

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 Ints. So we we fmap that function over idGetters, we get a list of lists of Ints, 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.

Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
  • Many thanks Robin for the lambda expression for ($ p) I finally understand how it works. But also how could we express (fmap ($ p)) idGetters with function composition? – Mahmut Salman May 22 '22 at 00:40
  • 1
    That expression is not a function (it's of type `[[Int]]`) so you can't express it as a function composition. Perhaps you mean `ids`, which is `\p -> (fmap ($ p)) idGetters` - in which case you can write it as a composition, eg `(flip $ idGetters) . fmap . (flip $)` (I think - I have haven't tested it). But there's no real gain to write every function definition in such a semi-cryptic way. – Robin Zigmond May 22 '22 at 07:50
  • 1
    Too late to edit but that `flip $ idGetters` is totally wrong - I meant `flip ($) idGetters`, although really that's better expressed as a section `($ idGetters)`. – Robin Zigmond May 22 '22 at 08:39