惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
NISL@THU
NISL@THU
Know Your Adversary
Know Your Adversary
The Hacker News
The Hacker News
D
Docker
Scott Helme
Scott Helme
有赞技术团队
有赞技术团队
罗磊的独立博客
A
Arctic Wolf
P
Privacy International News Feed
Google DeepMind News
Google DeepMind News
Spread Privacy
Spread Privacy
B
Blog
A
About on SuperTechFans
L
LINUX DO - 最新话题
博客园 - 司徒正美
T
The Blog of Author Tim Ferriss
P
Proofpoint News Feed
W
WeLiveSecurity
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Google DeepMind News
Google DeepMind News
aimingoo的专栏
aimingoo的专栏
T
The Exploit Database - CXSecurity.com
美团技术团队
J
Java Code Geeks
Cloudbric
Cloudbric
雷峰网
雷峰网
Vercel News
Vercel News
P
Proofpoint News Feed
Webroot Blog
Webroot Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
人人都是产品经理
人人都是产品经理
Martin Fowler
Martin Fowler
G
Google Developers Blog
T
Tenable Blog
PCI Perspectives
PCI Perspectives
Engineering at Meta
Engineering at Meta
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
H
Hackread – Cybersecurity News, Data Breaches, AI and More
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
C
Cybersecurity and Infrastructure Security Agency CISA
S
Secure Thoughts
N
News and Events Feed by Topic
GbyAI
GbyAI
S
SegmentFault 最新的问题
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org

Romes' Blog RSS Feed

Running out of Disk Space in Production How I turned my Anki side project into a Kickstarter: A Walkthrough Haskell Debugger for GHC 9.14 Lazy Linearity for a Core Functional Language (POPL 2026) Automatically Packaging a Haskell Library as a Swift Binary XCFramework Implementing Unsure Calculator in 100 lines of Haskell Planning Weekly Workouts in 100 lines of Haskell Calling Haskell from Swift Creating a macOS app with Haskell and Swift Introducing ghc-toolchain to GHC Writing prettier Haskell with Unicode Syntax and Vim Monthly Update on a Haskell Game Engine Equality Saturation in Haskell, a tutorial Graphical Applications in Haskell with FRP and Reflex Graphical Applications in Haskell with MVC and Gloss Haskell 102 Lecture Notes Haskell 101 Lecture Notes
Computed Properties for Haskell Records
Rodrigo Mesq · 2023-11-30 · via Romes' Blog RSS Feed

Records in Haskell

Haskell has so-called record types, which are also commonly known as structs, for instance, in C, Swift, and Rust. To define a square, one would write:

data Point
  = Point
    { x :: Int
    , y :: Int
    }

data Square
  = Square
    { topLeft     :: Point
    , bottomRight :: Point
    }

mySquare = Square{ topLeft = Point{x = 0, y = 0}
                 , bottomRight = Point{x = 2, y = 2} }
mySquareWidth = x (bottomRight mySquare) - x (topLeft mySquare)

In Haskell record types are just syntactic sugar for ordinary product types paired with functions that get and set these fields. In essence, the above is not fundamentally different from having the following standard product types and functions:

data Point = Point Int Int
data Square = Square Point Point

x, y :: Point -> Int
x (Point px _) = px
y (Point _ py) = py

topLeft, bottomRight :: Square -> Point
topLeft (Square tl _) = tl
bottomRight (Square _ br) = br

-- And setters...

Overloaded Record Dot

However, by turning on the OverloadedRecordDot syntax extension, you can use more syntactic sugar to project the fields of a record instead of using the field name as a standard function:

{-# LANGUAGE OverloadedRecordDot #-}
mySquareWidth = mySquare.bottomRight.x - mySquare.topLeft.x

which is neat! I like OverloadedRecordDot. It looks clean and feels more like using proper property of the record data type. It is also less ambiguous for an LSP to suggest the record properties of a data type by typing after the ., than it is to suggest functions to apply to the record type argument.

Named Field Puns

Since I’m already writing about records, I’ll mention another extension I quite enjoy: NamedFieldPuns.

Traditionally, when matching on a record, you can list the field names and bind variables to the value associated with that field. Continuing the above example:

area :: Square -> Int
area Square{topLeft = tl, bottomRight = br}
    = (br.x - tl.x) * (br.y - tl.y)

We know, however, that naming things is hard and best avoided. With NamedFieldPuns, instead of declaring the variable to be bound to the right of the field name, we have the field name be the variable bound to its value:

area :: Square -> Int
area Square{topLeft, bottomRight}
    = (bottomRight.x - topLeft.x) * (bottomRight.y - topLeft.y)

There are more record-related extensions, such as RecordWildCards or OverloadedRecordUpdate, which I will not get into, but that can also make life smoother when working with records.

Computed Properties

Computed properties are a (not-particularly-exclusive-to) Swift concept I’ve recently come accross while working on my interoperability between Haskell and Swift project.

Here is a definition from the Swift book section on (computed) properties:

Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value. Computed properties are provided by classes, structures, and enumerations. Stored properties are provided only by classes and structures.

And a Swift example, where the volume is a property computed from the width, the height and the depth of a Cuboid:

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        return width * height * depth
    }
}

C# also has a notion of computed properties. In Java, simple class methods computing a result from class properties can also be seen as some sort of computed property, or, really, class methods in any object oriented language.

In Haskell, as basically everything else, you can think of computed properties as… just functions. But there is one key element to computed properties that makes them different from just functions – them being called using dot syntax at a value of a record type just like any other property, and the evoking the idea of describing a property of the record type.

Can we have that kind of computed properties in Haskell? Well, of course!

Following the examples in previous sections, consider the area function to be conceptually a computed property of a rectangle, as it uses the two Square properties (topLeft and bottomRight) to compute a new one. Ultimately, we want to be able to type:

To achieve this, we need to emulate the behaviour of field accessors. The key insight is to use the HasField class just like default field accessors do. HasField enables so-called record field selector polymorphism and allows us to not only define functions to operate on any record type with eg a field named name, it allows us to define field accessors for non-record types, and, ultimately, allows us to create computed properties. The ability to define our own instances of HasField is also documented in the user guide under virtual record fields.

To make the area function a field accessor, thereby making it a record-dot-enabled-computed-property, we instance HasField using the field name area (which is a defined as a type-level string in the first argument to HasField):

{-# LANGUAGE GHC2021, OverloadedRecordDot, DataKinds #-}
import GHC.Records

instance HasField "area" Square Int where
    getField = area

You can now write some_square.area to compute the area of the square based on its record properties.

Here’s an example of a full program defining another computed property and printing it:

{-# LANGUAGE GHC2021, OverloadedRecordDot, DataKinds #-}

import GHC.Records

data User = User
  { birthYear :: Int
  , name :: String
  }

instance HasField "age" User Int where getField = age

age :: User -> Int
age u = 2023 - u.birthYear

user :: User
user = User{birthYear=1995, name="Robert"}

main = print user.age

Conclusion

This has been a whirlwhind thought kind of post. I am not currently using this in any project. I thought “I suppose we can also have this neat properties sugar” and tried it, this is only my exposition of the idea.

In my opinion, this could be handy as some functions can really be better thought of as properties of a datatype, and doing so doesn’t preclude you from also using it as a function in cases where it reads more naturally (and of course, pass it on to higher order functions). LSP based autocompletion of (computed) properties after the dot might be another positive factor. It is probably also a Haskell anti-pattern for some!

I’m left wondering: is anyone out there doing this?