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?
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
A compiler error about foo
and bar
having different types inside ==
comparison.
It compiles successfully.
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.