Abstracts of recurring applications in Monad chains

Haskell wikibook has an example that shows how the lookup command chain when trying to find different pieces of related information in a database, here:

 getTaxOwed :: String -- their name -> Maybe Double -- the amount of tax they owe getTaxOwed name = lookup name phonebook >>= (\number -> lookup number governmentDatabase) >>= (\registration -> lookup registration taxDatabase) 

and rewritten in the notation do :

 getTaxOwed name = do number <- lookup name phonebook registration <- lookup number governmentDatabase lookup registration taxDatabase 

Now, when I see a function that repeats several times, I immediately try to think about ways to abstract by re-applying it, but since I have not used Monads in practice yet, and since they seem to be at a fairly high level of abstraction, I did not know how to approach this in this case.

What are some ways, if any, that the encoder can abstract over the general pattern above, that is, call lookup on each line?

(aside: is this the appropriate context for the phrase “abstraction”? I felt that it caught my point, but I'm not sure, and I would like to make sure that I use the terminology correctly as a relatively new encoder, I looked at other posts that clarified its use and meaning, but I still can not figure it out for a specific example)

+4
source share
1 answer

Thank you very much Karsten for the link to foldM ! Thank them for understanding this answer.

So, if we use foldM , we can write a function that repeatedly executes a lookup chain encoded through several directories that depend on each previous result. If, thanks to the use of monads , at any point in the lookup current key cannot be found in the directory, it will end and return Nothing :

 lookupALot :: Eq a => a -> [(a,b)] -> Maybe b lookupALot key directories = foldM lookup key directories 

it takes the form of a form

  foldM f k1 [d1, d2, ..., dm] -- k == key, d == directory == do k2 <- f k1 d1 k3 <- f k2 d2 ... f km dm 

which is the same structure as

  do number <- lookup name phonebook registration <- lookup number governmentDatabase lookup registration taxDatabase 

Therefore, a more compact way to write getTaxOwed would be:

 getTaxOwed :: String -> Maybe Double getTaxOwed name = foldM lookup name [phonebook, governmentDatabase, taxDatabase] 

What a view it takes me! This line of code will find the phone number associated with the person name , then check the governmentDatabase with their number on their registration and finally find your tax information from this registration . Note that this will only work for data in the form [(a,b)] , as indicated by the lookupALot type.

+2
source

All Articles