Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Records (with optics?) #9

Open
chris-martin opened this issue Sep 30, 2019 · 3 comments
Open

Records (with optics?) #9

chris-martin opened this issue Sep 30, 2019 · 3 comments
Labels
good for new contributors Pull requests welcome! new example This issue is about writing a new example program.

Comments

@chris-martin
Copy link
Member

Here's a records demo we wrote a while back:

import Numeric.Natural

data Person =
  Person
    { name :: String  -- ^ The person's given name
    , age :: Natural  -- ^ How many years old
    }
    deriving Show

main =
  do
    let a = Person { name = "Alice", age = 47 }
    let b = Person { name = "Bob", age = 50 }
    let c = b{ age = 51 }

    putStrLn (show a)
    putStrLn (show b)
    putStrLn (show c)

    putStrLn ("name: " ++ name c)
    putStrLn ("age: " ++ show (age c))
$ runhaskell records.hs
Person {name = "Alice", age = 47}
Person {name = "Bob", age = 50}
Person {name = "Bob", age = 51}
name: Bob
age: 51

Lately I'm feeling like the Phrasebook should just immediately introduce optics from the start.

{-# LANGUAGE TemplateHaskell #-}

import Numeric.Natural
import Optics

data Person =
  Person
    { _name :: String  -- ^ The person's given name
    , _age :: Natural  -- ^ How many years old
    }
    deriving Show

makeLenses ''Person

main =
  do
    let a = Person { _name = "Alice", _age = 47 }
    let b = Person { _name = "Bob", _age = 50 }
    let c = set age 51 b

    putStrLn (show a)
    putStrLn (show b)
    putStrLn (show c)

    putStrLn ("name: " ++ view name c)
    putStrLn ("age: " ++ show (view age c))

Maybe that's too radical. On the other hand, maybe introducing it now in an extremely simple context is good setup for a later page on doing "deep updates" with composed lenses. I think in a later page we could end up showing how to get a lot of of optics using only view, set, over, and (%) without being overwhelming.

@chris-martin chris-martin added good for new contributors Pull requests welcome! new example This issue is about writing a new example program. labels Sep 30, 2019
@cideM
Copy link
Contributor

cideM commented Oct 13, 2019

Since I really like the idea of introducing optics as if it was something super simply and approachable and wanted to check out that new package anyway I'll get on it 💯

@friedbrice
Copy link
Contributor

friedbrice commented Nov 4, 2019

Lately I'm feeling like the Phrasebook should just immediately introduce optics from the start.

If that is a road you want to go down, I'd recommend taking a hard look at going the path of generic-lens (https://hackage.haskell.org/package/generic-lens) and generic-lens-labels (http://hackage.haskell.org/package/generic-lens-labels) rather than that of makeLenses. With the two above-mentioned packages, you get to avoid any magic strings in the names of your record fields. Access and manipulation looks like view #name person and over #name (map toUpper) person, respectively. Slightly annoyingly, you need to import the two libraries and set XOverloadedLabels in each module where you want to use this syntax, though, which maybe outweighs any potential gain.

I'm a big fan of generic-lens, but I can see why you might not want to use it. In your case, it's not an engineering trade-off and a pedagogical trade-off.

@friedbrice
Copy link
Contributor

Either way you want to get your lenses, records with optics up front is--I think--the right way to go. Using optics to modify a deeply-nested field is a way in which Haskell records are genuinely, objectively better than imperative languages. E.g. in imperative code, you can use += to apply a (terribly specific) function to a deeply-nested field (of a very specific type), whereas over lets you do that for any function at any type! I think you should showcase that :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good for new contributors Pull requests welcome! new example This issue is about writing a new example program.
Projects
None yet
Development

No branches or pull requests

3 participants