Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching against a type with only one constructor

If I pattern-match against an expression whose type has only one constructor, will that still force the runtime to evaluate the expression to WHNF?


I did an experiment that seems to indicate it doesn't evaluate:

Prelude> data Test = Test Int Int
Prelude> let errorpr () = error "Fail"
Prelude> let makeTest f = let (x,y) = f () in Test x y
Prelude> let x = makeTest errorpr
Prelude> let Test z1 z2 = x
Prelude> :sprint z1
z1 = _
Prelude> :sprint z2
z2 = _
Prelude> :sprint x
x = _

I would have expected to either get an error or :sprint x to yield

x = Test _ _

but it didn't.


Apparently I didn't understand how "let" works. See the answers below

like image 925
dspyz Avatar asked Dec 18 '25 14:12

dspyz


1 Answers

Prelude> let x = makeTest errorpr
Prelude> let Test z1 z2 = x

The last line does not force the evaluation of anything: patterns within let are (implicitly) lazy patterns (aka irrefutable patterns). Try instead

Prelude> let x = makeTest errorpr
Prelude> case x of Test z1 z2 -> "hello!"
Prelude> :sprint x

and you should observe something like Test _ _, since patterns in case are not lazy ones. By comparison,

Prelude> let x = makeTest errorpr
Prelude> case x of ~(Test z1 z2) -> "hello!"   -- lazy pattern!
Prelude> :sprint x

should print just _, like when using let.

The above holds for data types. Instead, newtypes do not lift the internal type, but directly use the same representation. That is, newtype value construction and pattern-matching are no-ops at runtime: they are roughly erased by the compiler after type checking.

like image 68
chi Avatar answered Dec 21 '25 06:12

chi