How to read the syntax `Typ{..}` in haskell? [duplicate] - haskell

This question already has an answer here:
pattern matching of the form: Option{..} <-
(1 answer)
Closed 4 years ago.
While reading library code here I have noticed a really weird looking syntax that I can't make sense of:
momenta
:: (KnownNat m, KnownNat n)
=> System m n
-> Config n
-> R n
momenta Sys{..} Cfg{..} = tr j #> diag _sysInertia #> j #> cfgVelocities
-- ^^^^^^^^^^^^^^^ the syntax in question
where
j = _sysJacobian cfgPositions
The relevant definitions of System includes a record { _sysJacobian :: R n -> L m n }, and { cfgVelocities :: R n } is part of the record declaration of Config so I believe I know what the code does, I think the code is quite readable, props to the author.
The question is: what is this syntax called and how exactly can I use it?

In short: it is an extension of GHC called RecordWildCards.
In Haskell you can use record syntax to define data types. For example:
data Foo = Bar { foo :: Int, bar :: String } | Qux { foo :: Int, qux :: Int }
We can then pattern match on the data constructor, and match zero or more parameters, for example:
someFunction :: Int -> Foo -> Foo
someFunction dd (Bar {foo=x}) = dd + x
someFunction dd (Qux {foo=x, qux=y}) = dd + x + y
But it can happen that we need access to a large amount (or even all) parameters. Like for example:
someOtherFunction :: Foo -> Int
someOtherFunction (Bar {foo=foo, bar=bar}) = foo
someOtherFunction (Qux {foo=foo, qux=qux}) = foo + qux
In case the number of parameters is rather large, then this becomes cumbersome. There is an extension RecordWildCards:
{-# LANGUAGE RecordWildCards #-}
this will implicitly write for every parameter foo, foo=foo if you write {..} when we do record pattern matching.
So we can then write:
someOtherFunction :: Foo -> Int
someOtherFunction (Bar {..}) = foo
someOtherFunction (Qux {..}) = foo + qux
So here the compiler implicitly pattern matched all parameters with a variable with the same name, such that we can access those parameters without explicit pattern matching, nor by using getters.
The advantage is thus that we save a lot on large code chunks that have to be written manually. A downside is however the fact that the parameters are no longer explicitly and hence the code is harder to understand. We see the use of parameters for which there exist actually getter counterparts, and thus it can introduce some confusion.
Like #leftroundabout says, probably lenses can do the trick as well, and it will prevent introducing variables that basically shadow getters, etc.
You can also merge the RecordWildCards with pattern matching on parameters, for example:
someOtherFunction :: Foo -> Int
someOtherFunction (Bar {bar=[], ..}) = foo
someOtherFunction (Bar {..}) = foo + 42
someOtherFunction (Qux {..}) = foo + qux
So here in case the bar parameter of a Foo instance with a Bar data constructor is the empty string, we return the foo value, otherwise we add 42 to it.

It's the RecordWildCards syntax extension. From the docs:
For records with many fields, it can be tiresome to write out each field individually in a record pattern ... Record wildcard syntax permits a ".." in a record pattern, where each elided field f is replaced by the pattern f = f ... The expansion is purely syntactic, so the record wildcard expression refers to the nearest enclosing variables that are spelled the same as the omitted field names.
Basically it brings the fields of a record into scope.
It is particularly useful when writing encoders/decoders (e.g. Aeson), but should be used sparingly in the interest of code clarity.

Related

Type synonyms with TemplateHaskell

If I have a type data Foo = Foo Int Int where frequently (but not always) the second parameter is a (fixed) function of the first, I could write a helper function mkFoo m = Foo m (f m) to reduce duplication.
I have this exact problem, but at the type level. The natural solution might be to use singletons to promote f, but my f isn't easily promoted. Instead, I'm trying to use TemplateHaskell and reflection to evaluate f at compile time at the data level. For example, I can currently do this (using ‑XDataKinds and GHC.TypeLits):
f :: Integer -> Integer
data Bar (a::Nat) (b::Nat)
mkNat :: Integer -> Q Type -- constructs a TypeLit
bar :: Bar 5 $(mkNat $ f $ proxy natValue (Proxy::Proxy 5))
It's obviously annoying to have to write this with a concrete type every time I want to use this pattern. Unfortunately, I know of no shorter or generic way to write the signature for bar. In particular, I can't define the type synonym
type Bar' (m :: Nat) = Bar m $(mkNat $ f $ proxy natVal (Proxy::Proxy m))
bar :: Bar' 5
due to TH stage restrictions (m is not imported or known when compiling the synonym).
Is there any way to simplify the signature of bar?

What is the idiomatic way to access part of Algebraic data type in Haskell?

There is an easier way to call function test with value x than using case expression?
data FooBar = Foo Int | Bar String
test :: Maybe Int -> Bool -- Int from Foo constructor
x :: FooBar
One easier way is to define a helper to get you part of the way there:
data FooBar = Foo Int | Bar String
foo :: FooBar -> Maybe Int
foo (Foo x) = Just x
foo _ = Nothing
test :: Maybe Int -> Bool
x :: FooBar
result :: Bool
result = test . foo $ x
If you're the one defining test, you could also just define it differently to make things easier on yourself:
test' :: FooBar -> Bool
test' (Foo x) = (some logic)
test' _ = (the default value)
There is a neat concept called a "prism" that models this general concept -- extracting pieces of data from sum types -- elegantly. But they're... kind of hard to understand, and whether or not they can be considered "idiomatic" is pretty controversial.
You could use guards or pattern matching in the functions you are handing a FooBar as an argument.

Data constructors without breaking the open/closed principle

I have a data constructor like this
class FooClass a where
foo :: a -> b
class BarClass a where
bar :: a -> b
data FooBar = Foo :: FooClass a => a -> IO ()
| Bar :: BarClass a => a -> IO ()
So that I can use pattern matching:
foobar :: FooBar -> a -> IO ()
foobar (Foo f) x = f (foo x)
foobar (Bar f) x = f (bar x)
However, this breaks the open/closed principle.
I'd like to be able to extend FooBar with additional methods based on other classes.
How would I implement this in Haskell?
As others have pointed out, this code is flawed in ways that obscure your question. It's also probably dangerous to try to think too hard about how OO principles translate to FP. They have a place, because much of OO is embedded in FP naturally, but it's much better to learn FP directly first and then observe the laws later as certain special cases.
In particular, we can talk about how greater refinement of types is a form of extension. For instance, comparing the types like
(Num a) => a -> IO ()
(Num a, Show a) => a -> IO ()
we can talk about how the second function takes in a set of types which is a natural subtype of the inputs to the first function. In particular, the set of possible types that can be input to the second function is a refinement of the inputs to the first. As users of these functions, there are fewer valid ways to use the second function. As implementers of these functions, there are more valid ways to implement the second function. In fact, we know the following
All values which are valid inputs to the second function are also valid inputs to the first
All functions which are correctly typed by the first signature are also correctly typed by the second.
This duality between giving and taking is explored in the study of Game semantics. The idea of "open for extension" plays out trivially in that we can always decide to ask for a more refined type, but it's almost completely uninteresting since that's just obvious in how refined types are used.
So what about ADTs (data declarations) directly? Are then Open/Closed? Mu—ADTs aren't objects, so the rule does not apply directly.
The trick to doing your example in Haskell is to use functions instead of classes:
-- FooBar is like a base class
-- with methods foo and bar.
-- I've interpreted your example liberally
-- for purposes of illustration.
-- In particular, FooBar has two methods -
-- foo and bar - with different signatures.
data FooBar = FooBar {
foo :: IO (),
bar :: Int -> Int
}
-- Use functions for classes, like in Javascript.
-- This doesn't mean Haskell is untyped, it just means classes are not types.
-- Classes are really functions that make objects.
fooClass :: Int -> FooBar
fooClass n = FooBar {
foo = putStrLn ("Foo " ++ show n)
bar = \n -> n+1
}
barClass :: FooBar
barClass = FooBar {
foo = putStrLn "Bar ",
bar = \n -> n * 2
}
-- Now we can define a function that uses FooBar and it doesn't matter
-- if the FooBar we pass in came from fooClass, barClass or something else,
-- bazClass, say.
foobar (FooBar foo bar) = do
-- invoke foo
foo
-- use bar
print (bar 7)
Here FooBar is 'open for extension' because we can create as many FooBar values as we like with different behaviours.
To 'extend' FooBar with another field, baz, without changing FooBar, fooClass or barClass, we need to declare a FooBarBaz type that includes a FooBar. We can still use our foobar function, we just have to first extract the FooBar from the FooBarBaz first.
So far, I've been keeping close to OOP. This is because Bertrand Meyer worded the open closed principle to require OOP or something very like it:
software entities (classes, modules, functions, etc.) should be open
for extension, but closed for modification
In particular, the word "extension" is traditionally interpreted as meaning "subclassing". If you're prepared to interpret the principle as merely "having extension points", then any function that takes another function as parameter is "open for extension". This is so common in functional programming that it's not considered a principle. The "parameterisation principle" just doesn't sound the same.

Pattern matching against record syntax

Consider the following data definition:
data Foo = A{field::Int}
| B{field::Int}
| C
| D
Now let's say we want to write a function that takes a Foo and increases field if it exists, and leave it unchanged otherwise:
incFoo :: Foo -> Foo
incFoo A{field=n} = A{field=n+1}
incFoo B{field=n} = B{field=n+1}
incFoo x = x
This naive approach leads to some code duplication. But the fact that both A and B shares field allows us to rewrite it:
incFoo :: Foo -> Foo
incFoo x | hasField x, n <- field x = x{field=n+1}
incFoo x = x
hasField A{} = True
hasField B{} = True
hasField _ = False
Less elegant, but that's defiantly easier to maintain when the actual manipulation is complex. The key feature here is x{field=n+1} - record syntax allows us to "update" field without specifying x's type. Considering this, I'd expect something similar to the following syntax (which is not supported):
incFoo :: Foo -> Foo
incFoo x{field=n} = x{field=n+1}
incFoo x = x
I've considered using View Patterns, but since field is a partial function (field C raises an error) it'll require wrapping it in more boilerplate code.
So my question is: why there's no support for the above syntax, and is there any elegant way of implementing a similar behavior?
Thanks!
The reason why you can't do this is because in Haskell, records are inherently second class. They always must be wrapped in a constructor. So in order to have this work as intended you either must use an individual case for each constructor, or use a record substitute.
One possible solution is to use lenses. I'll use the implementation of lenses lens since lens-family-th doesn't seem to handle duplicate field names.
import Control.Lens
data Foo = A {_f :: Int}
| B {_f :: Int}
deriving Show
makeLenses ''Foo
foo :: Foo -> Foo
foo = f %~ (+1)
And then we can use it like this
> foo (A 1)
A{_f = 1}

Omitting constructor arguments in Haskell case statements

Omitting function arguments is a nice tool for concise Haskell code.
h :: String -> Int
h = (4 +) . length
What about omitting data constructor arguments in case statements. The following code might be considered a little grungy, where s and i are the final arguments in A and B but are repeated as the final arguments in the body of each case match.
f :: Foo -> Int
f = \case
A s -> 4 + length s
B i -> 2 + id i
Is there a way to omit such arguments in case pattern matching? For constructors with a large number of arguments, this would radically shorten code width. E.g. the following pseudo code.
g :: Foo -> Int
g = \case
{- match `A` constructor -> function application to A's arguments -}
A -> (4 +) . length
{- match `B` constructor -> function application to B's arguments -}
B -> (2 +) . id
The GHC extension RecordWildCards lets you concisely bring all the fields of a constructor into scope (of course, this requires you to give names to those fields).
{-# LANGUAGE LambdaCase, RecordWildCards #-}
data Foo = Foo {field1, field2 :: Int} | Bar {field1 :: Int}
baz = \case
Foo{..} -> 4 + field2
Bar{..} -> 2 + field1
-- plus it also "sucks in" fields from a scope
mkBar400 = let field1 = 400 in Bar{..}
`
You can always refactor case statements on constructors into a single function so that from then on you only pass your concise function definitions as arguments to these specific functions. Allow me to illustrate.
Consider the Maybe a datatype:
data Maybe a = Nothing | Just a
Should you now need to define a function f :: Maybe a -> b (for some fixed b and perhaps also a), instead of writing it like
f Nothing = this
f (Just x) = that x
you could start by first defining a function
maybe f _ Nothing = f
maybe _ g (Just x) = g x
and then f can by defined as maybe this that. Pretty much as what happens with all the familiar recursion patterns.
This way you're effectively refactoring out case statements. The code gets arguably cleaner and it does not require language extensions.

Resources