compiler-errorsrecordtype-safetypurescript

How to make different record `type`s unequal


I am learning PureScript due to not being satisfied (in particular) with TypeScript's type safety of what's called "records" in PS. While doing so I stumble upon the exact same problem in PS, do I miss something?

Given these two types:

type Foo = {a :: Int}
type Bar = {a :: Int}

Comparing them gives no compiler error! So type is more like an alias and isn't actually a type.

"PureScript by Example" uses it exactly to define types though and calls them "records". So I thought: maybe there's confusion and PureScript "records" aren't the records in Haskell-sense. I went searching PS vs Haskell syntax comparision, and lo and behold, it said to be the data from Haskell. Indeed PS hasn't a newtype or data keywords. (actually, apparently there is a separate package Data.Newtype, but, well, it is a separate package; and I'm also not sure how well it'd work for getting rid of type completely in preference of newtype).

I do realize that in Haskell similar code:

data Foo = Foo {a :: Int}
data Bar = Bar {a :: Int}

…will result in Multiple declarations of ‘a’. But it is important: the compiler will error out. There is type-safety, I can't accidentally make different types with same fields or compare different types.

Can't I achieve the same behavior in PureScript?

Steps to reproduce

Build the following PureScript code:

module Main where

import Prelude

import Effect (Effect)
import Effect.Console (log)

type Foo = {a :: Int}
type Bar = {a :: Int}

foo :: Foo
foo = {a : 1}

bar :: Bar
bar = {a : 1}

main :: Effect Unit
main = do
  log $ show $ foo == bar

Expected

A compiler error about foo and bar having different types inside == comparison.

Actual

It compiles successfully.


Solution

  • Yes, PureScript does very much have newtype and data keywords, and they do behave exactly like in Haskell.

    newtype Foo = Foo { a :: Int }
    newtype Bar = Bar { a :: Int }
    

    Well, almost exactly. Unlike in Haskell, this won't actually cause "double declaration of a", because PureScript, unlike Haskell, has real records. With real fields. Not just globally scoped accessor functions.