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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With