Nested collection functions and comprehensions

Hi, I’ve recently started learning F# using the currently MEAP book F# in Action and Grokking functional programming (which uses Scala for code demonstrations).

I’ve been doing an example on nested collection functions, where author of the FP book mentioned Comprehensions as a cleaner way of representing nested collection functions, and I can’t seem to find an equivalent in F# anywhere.

Currently, my code looks like this :

type Book = {
    Title : string
    Authors : string list
}

type Movie = {
    Title : string
}

let books = [
    { Title = "FP in Scala"; Authors = ["Chiusano"; "Bjarnason"] }
    { Title = "The Hobbit"; Authors = ["Tolkien"]}
    { Title = "Modern Java in Action"; Authors = ["Urma"; "Fusco"; "Mycroft"]}
]

let bookAdaptations author = 
    if author = "Tolkien" then [{ Title = "An Unexpected Journey"}; { Title = "The Desolation of Smaug"}] 
    else List.empty

let recommendationFeed (books : Book list) = 
    books
    |> List.collect (fun book ->
         book.Authors 
         |> List.collect (fun author -> 
            author 
            |> bookAdaptations
            |> List.map (fun movie -> $"You may also like {movie.Title} because you liked {author}'s {book.Title}")))

This isn’t very readable. The problem is, I need book, author and a movie in order to output a desired message (hence the nesting). Is there a way to make this more readable in F# (without nesting anything)? Author of the Grokking FP book uses syntax similar to this:

for {
 book <- books
 author <- book.authors
 movie <- bookAdaptations(author)
} yield ...

Thanks!

Okay, after some more experimentation I managed to solve it using

let recommendationFeedV2 (books : Book list) = 
    [for book in books do
     for author in book.Authors do
     for movie in author |> bookAdaptations do 
        yield $"You may also like {movie.Title} because you liked {author}'s {book.Title}"]

Looks similar to the LINQ syntax.

2 Likes