I’m trying to access nested data (Foo.y
inside Bar
in the example below), but the straightforward approaches for unwrapping Foo
inside Bar
that come to mind do not work. But how to unwrap it correctly?
Here my data:
module Foo where
import Prelude
data Foo = Foo { y :: Int }
data Bar = Bar { x :: Int
, foo :: Foo }
The following (of course) does not compile, error is Could not match type { y :: Int } with type Foo
— just like Bar
, Foo
needs unwrapping first:
fn1 :: Bar -> Int
fn1 (Bar { x, foo }) = x + foo.y
So I put up my hopes for the following, but alas, compiler says “no” (parentheses around Foo
constructor don’t help):
fn2 :: Bar -> Int
fn2 (Bar { x, Foo { y } }) = x + y
fn3 :: Bar -> Int
fn3 (Bar { x, Foo f }) = x + f.y
The following works, using a helper function to do the unwrapping, but there has got to be a better way:
getY (Foo foo) = foo -- helper function
fn4 :: Bar -> Int
fn4 (Bar { x, foo }) = let foo2 = getY foo in
x + foo2.y
So, how do I do nested “unwrap”?
[EDIT]
After an hour or two of trying things out, I came up with this, which works:
fn5 :: Bar -> Int
fn5 (Bar { x, foo = (Foo f) }) = x + f.y
Is this the idiomatic way to do it? Why don’t fn2
and fn3
work?
Functions fn2 and fn3 do not work because the compiler does not know which record field you are referring to (foo). You have to reference record fields by name.
Function fn4 is a perfectly fine solution (although your naming is pretty confusing, getY actually returns the wrapped record inside the Foo constructor, not the y value).
As far as I can tell, fn5 is the shortest possible solution. I would personally prefer a helper function (like in your fourth example):
getY :: Foo -> Int
getY (Foo rec) = rec.y
fn6 :: Bar -> Int
fn6 (Bar { x, foo }) = x + getY foo