As a datapoint, Haskell is a general-purpose programming language that separates side-effecting computations from pure ones by their type. Side-effecting computations can only be assembled by explicitly sequencing their parts. The compiler consequently assumes that subexpressions that are not sequenced can be moved and shared freely without making further checks.
By use of unsafePerformIO, a side-effecting operation can be made to appear as a pure one, breaking the compiler’s assumptions and thus requiring great care to use safely, hence the name.
See this code on the Haskell playground: https://play.haskell.org/saved/3EKCXKM9
It demonstrates that using unsafePerformIO to place an access to a global random generator inside a list comprehension has similar caveats to the random join: With no optimization (-O0), the call is left in place and a new boolean is generated for each element, resulting in results hovering closely around 500000, while with optimization (-O1), the apparently-constant subexpression is floated out and turned into a global constant that is initialized on first use, so that each run of the program either outputs 0 or 1000000.
As a datapoint, Haskell is a general-purpose programming language that separates side-effecting computations from pure ones by their type. Side-effecting computations can only be assembled by explicitly sequencing their parts. The compiler consequently assumes that subexpressions that are not sequenced can be moved and shared freely without making further checks. By use of unsafePerformIO, a side-effecting operation can be made to appear as a pure one, breaking the compiler’s assumptions and thus requiring great care to use safely, hence the name. See this code on the Haskell playground: https://play.haskell.org/saved/3EKCXKM9 It demonstrates that using unsafePerformIO to place an access to a global random generator inside a list comprehension has similar caveats to the random join: With no optimization (-O0), the call is left in place and a new boolean is generated for each element, resulting in results hovering closely around 500000, while with optimization (-O1), the apparently-constant subexpression is floated out and turned into a global constant that is initialized on first use, so that each run of the program either outputs 0 or 1000000.