StateT and non-determinism monad: a simple example - haskell
As part of learning how to work with StateT and the nondeterminism monad, I'd like to write a function which uses these to enumerate the partitions of an integer (while being allowed to reuse integers). For example, passing an argument of 4 should result in [[1,1,1,1],[1,1,2],[2,2],[1,3],[4]] (uniqueness doesn't matter, I'm more concerned with just getting to working code).
(Also, I'm aware that there's a recursive solution for generating partitions as well as dynamic programming and generating function based solutions for counting partitions - the purpose of this exercise is to construct a minimal working example that combines StateT and [].)
Here's my attempt that was designed to work on any input less than or equal to 5:
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wall #-}
import CorePrelude
import Control.Monad.State.Lazy
sumState :: StateT Int [] [Int]
sumState = do
m <- lift [1..5]
n <- get <* modify (-m+)
case compare n 0 of
LT -> mzero
EQ -> return [m]
GT -> fmap (n:) sumState
runner :: Int -> [([Int],Int)]
runner = runStateT sumState
I'm using runStateT rather than evalStateT to help with debugging (it's helpful to see the final state values). Like I said, I'm not too worried about generating unique partitions since I'd first like to just understand the correct way to use these two monads together.
Loading it in GHCi and evaluating runner 4 results in the following and I'm confused as to why the above code produces this output.
[([4,3,2,1,1],-1),([4,3,2,1,2],-2),([4,3,2,1,3],-3),([4,3,2,1,4],-4),([4,3,2,1,5],-5),([4,3,2,1],-1),([4,3,2,2],-2),([4,3,2,3],-3),([4,3,2,4],-4),([4,3,2,5],-5),([4,3,1,1],-1),([4,3,1,2],-2),([4,3,1,3],-3),([4,3,1,4],-4),([4,3,1,5],-5),([4,3,1],-1),([4,3,2],-2),([4,3,3],-3),([4,3,4],-4),([4,3,5],-5),([4,2,1,1],-1),([4,2,1,2],-2),([4,2,1,3],-3),([4,2,1,4],-4),([4,2,1,5],-5),([4,2,1],-1),([4,2,2],-2),([4,2,3],-3),([4,2,4],-4),([4,2,5],-5),([4,1,1],-1),([4,1,2],-2),([4,1,3],-3),([4,1,4],-4),([4,1,5],-5),([4,1],-1),([4,2],-2),([4,3],-3),([4,4],-4),([4,5],-5)]
What am I doing wrong? What's the correct way to combine StateT and [] in order to enumerate partitions?
You just have two little mistakes. The first is here:
n <- get <* modify (-m+)
This gets the value of n before we subtract m. You almost certainly want
n <- modify (-m+) >> get
instead, or
modify (-m+)
n <- get
if you prefer that spelling. The other is that you're putting the current state in the list instead of the value you're adding in the GT branch:
GT -> fmap (n:) sumState
Change that to
GT -> fmap (m:) sumState
and you're golden:
*Main> runner 4
[([1,1,1,1],0),([1,1,2],0),([1,2,1],0),([1,3],0),([2,1,1],0),([2,2],0),([3,1],0),([4],0)]
Related
Haskell Pattern Matching (beginner)
I have to implement a small programm in Haskell that increments/decrements a result by what in the console line is. For example if we have -a in the console the results must be 0, if -b the result must be incremented with 6 and so on. I have to do this with pattern matching. I haven't used Haskell until now and I find it pretty hard to understand. I have this to start with: import System.Environment main = getArgs >>= print . (foldr apply 0) . reverse apply :: String -> Integer -> Integer I don't understand what in the main is. What does it make and the reverse from end, what does it do? As I've read on the internet the getArgs function gives me the values from the console line. But how can I use them? Are there are equivalent functions like for/while in Haskell? Also, if you have some examples or maybe could help me, I will be very thankful. Thanks!
This is not beginner-friendly code. Several shortcuts are taken there to keep the code very compact (and in pointfree form). The code main = getArgs >>= print . (foldr apply 0) . reverse can be expanded as follows main = do args <- getArgs let reversedArgs = reverse args result = foldr apply 0 reversedArgs print result The result of this can be seen as follows. If the command line arguments are, say, args = ["A","B","C"], then we get reversedArgs = ["C","B","A"] and finally result = apply "C" (apply "B" (apply "A" 0)) since foldr applies the function apply in such way. Honestly, I'm unsure about why the code uses reverse and foldr for your task. I would have considered foldl (or, to improve performance, foldl') instead.
I expect the exercise is not to touch the given code, but to expand on it to perform your function. It defines a complicated-looking main function and declares the type of a more straight forward apply, which is called but not defined. import System.Environment -- contains the function getArgs -- main gets arguments, does something to them using apply, and prints main = getArgs >>= print . (foldr apply 0) . reverse -- apply must have this type, but what it does must be elsewhere apply :: String -> Integer -> Integer If we concentrate on apply, we see that it receives a string and an integer, and returns an integer. This is the function we have to write, and it can't decide control flow, so we can just get to it while hoping the argument handling works out. If we do want to figure out what main is up to, we can make a few observations. The only integer in main is 0, so the first call must get that as its second argument; later ones will be chained with whatever is returned, as that's how foldr operates. r stands for from the right, but the arguments are reversed, so this still processes arguments from the left. So I could go ahead and just write a few apply bindings to make the program compile: apply "succ" n = succ n apply "double" n = n + n apply "div3" n = n `div` 3 This added a few usable operations. It doesn't handle all possible strings. $ runhaskell pmb.hs succ succ double double succ div3 3 $ runhaskell pmb.hs hello? pmb.hs: pmb.hs:(5,1)-(7,26): Non-exhaustive patterns in function apply The exercise should be about how you handle the choice of operation based on the string argument. There are several options, including distinct patterns as above, pattern guards, case and if expressions. It can be useful to examine the used functions to see how they might fit together. Here's a look at a few of the used functions in ghci: Prelude> import System.Environment Prelude System.Environment> :t getArgs getArgs :: IO [String] Prelude System.Environment> :t (>>=) (>>=) :: Monad m => m a -> (a -> m b) -> m b Prelude System.Environment> :t print print :: Show a => a -> IO () Prelude System.Environment> :t (.) (.) :: (b -> c) -> (a -> b) -> a -> c Prelude System.Environment> :t foldr foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b Prelude System.Environment> :t reverse reverse :: [a] -> [a] This shows that all the strings come out of getArgs, it and print operate in the IO monad, which must be the m in >>=, and . transfers results from the right function into arguments for the left function. The type signature alone doesn't tell us what order foldr handles things, though, or what reverse does (though it can't create new values, only reorder including repetition). As a last exercise, I'll rewrite the main function in a form that doesn't switch directions as many times: main = print . foldl (flip apply) 0 =<< getArgs This reads from right to left in a data flow sense and handles arguments from left to right because foldl performs left-associative folding. flip is just there to match the argument order for apply.
As suggested in the comment, hoogle is a great tool. To find out what exactly you get from getArgs you can search for it on hoogle: https://hackage.haskell.org/package/base-4.11.1.0/docs/System-Environment.html#v:getArgs As you can see, it's of type IO [String]. Since I don't know how familiar you are with the IO abstractions yet, we'll just say that the right part of >>= gets those as argument. The arguments for a call like ./a.out -a -b --asdf Hi will then be a list of strings: ["-a", "-b", "--asdf", "Hi"]. The fold + reverse in the main will then do some magic, and your apply function will be called with each string in the list and the previous return value (0 for the first invocation). In Haskell, String is the same as [Char] with a bit of compiler sugar, so you can match on strings like you would on regular lists in your definition of apply.
What is the logic behind allowing only same Monad types to be concatenated with `>>` operator?
Though it is okay to bind IO [[Char]] and IO () but its not allowed to bind Maybe with IO. Can someone give an example how this relaxation would lead to a bad design? Why freedom in the polymorphic type of Monad is allowed though not the Monad itself?
There are a lot of good theoretical reasons, including "that's not what Monad is." But let's step away from that for a moment and just look at the implementation details. First off - Monad isn't magic. It's just a standard type class. Instances of Monad only get created when someone writes one. Writing that instance is what defines how (>>) works. Usually it's done implicitly through the default definition in terms of (>>=), but that just is evidence that (>>=) is the more general operator, and writing it requires making all the same decisions that writing (>>) would take. If you had a different operator that worked on more general types, you have to answer two questions. First, what would the types be? Second, how would you go about providing implementations? It's really not clear what the desired types would be, from your question. One of the following, I guess: class Poly1 m n where (>>) :: m a -> n b -> m b class Poly2 m n where (>>) :: m a -> n b -> n b class Poly3 m n o | m n -> o where (>>) :: m a -> n b -> o b All of them could be implemented. But you lose two really important factors for using them practically. You need to write an instance for every pair of types you plan to use together. This is a massively more complex undertaking than just an instance for each type. Something about n vs n^2. You lose predictability. What does the operation even do? Here's where theory and practice intersect. The theory behind Monad places a lot of restrictions on the operations. Those restrictions are referred to as the "monad laws". They are beyond the ability to verify in Haskell, but any Monad instance that doesn't obey them is considered to be buggy. The end result is that you quickly can build an intuition for what the Monad operations do and don't do. You can use them without looking up the details of every type involved, because you know properties that they obey. None of those possible classes I suggested give you any kind of assurances like that. You just have no idea what they do.
I’m not sure that I understand your question correctly, but it’s definitely possible to compose Maybe with IO or [] in the same sense that you can compose IO with []. For example, if you check the types in GHCI using :t, getContents >>= return . lines gives you an IO [String]. If you add >>= return . map Text.Read.readMaybe you get a type of IO [Maybe a], which is a composition of IO, [] and Maybe. You could then pass it to >>= return . Data.Maybe.catMaybes to flatten it to an IO [a]. Then you might pass the list of parsed valid input lines to a function that flattens it again and computes an output. Putting this together, the program import Text.Read (readMaybe) import Data.Maybe (catMaybes) main :: IO () main = getContents >>= -- IO String return . lines >>= -- IO [String] return . map readMaybe >>= -- IO [Maybe Int] return . catMaybes >>= -- IO [Int] return . (sum :: [Int] -> Int) >>= -- IO Int print -- IO () with the input: 1 2 Ignore this! 3 prints 6. It would also be possible to work with an IO (Maybe [String]), a Maybe [IO String], etc. You can do this with >> as well. Contrived example: getContents >> (return . Just) False reads the input, ignores it, and gives you back an IO (Maybe Bool).
Haskell's (<-) in Terms of the Natural Transformations of Monad
So I'm playing around with the hasbolt module in GHCi and I had a curiosity about some desugaring. I've been connecting to a Neo4j database by creating a pipe as follows ghci> pipe <- connect $ def {credentials} and that works just fine. However, I'm wondering what the type of the (<-) operator is (GHCi won't tell me). Most desugaring explanations describe that do x <- a return x desugars to a >>= (\x -> return x) but what about just the line x <- a? It doesn't help me to add in the return because I want pipe :: Pipe not pipe :: Control.Monad.IO.Class.MonadIO m => m Pipe, but (>>=) :: Monad m => m a -> (a -> m b) -> m b so trying to desugar using bind and return/pure doesn't work without it. Ideally it seems like it'd be best to just make a Comonad instance to enable using extract :: Monad m => m a -> a as pipe = extract $ connect $ def {creds} but it bugs me that I don't understand (<-). Another oddity is that, treating (<-) as haskell function, it's first argument is an out-of-scope variable, but that wouldn't mean that (<-) :: a -> m b -> b because not just anything can be used as a free variable. For instance, you couldn't bind the pipe to a Num type or a Bool. The variable has to be a "String"ish thing, except it never is actually a String; and you definitely can't try actually binding to a String. So it seems as if it isn't a haskell function in the usual sense (unless there is a class of functions that take values from the free variable namespace... unlikely). So what is (<-) exactly? Can it be replaced entirely by using extract? Is that the best way to desugar/circumvent it?
I'm wondering what the type of the (<-) operator is ... <- doesn't have a type, it's part of the syntax of do notation, which as you know is converted to sequences of >>= and return during a process called desugaring. but what about just the line x <- a ...? That's a syntax error in normal haskell code and the compiler would complain. The reason the line: ghci> pipe <- connect $ def {credentials} works in ghci is that the repl is a sort of do block; you can think of each entry as a line in your main function (it's a bit more hairy than that, but that's a good approximation). That's why you need (until recently) to say let foo = bar in ghci to declare a binding as well.
Ideally it seems like it'd be best to just make a Comonad instance to enable using extract :: Monad m => m a -> a as pipe = extract $ connect $ def {creds} but it bugs me that I don't understand (<-). Comonad has nothing to do with Monads. In fact, most Monads don't have any valid Comonad instance. Consider the [] Monad: instance Monad [a] where return x = [x] xs >>= f = concat (map f xs) If we try to write a Comonad instance, we can't define extract :: m a -> a instance Comonad [a] where extract (x:_) = x extract [] = ??? This tells us something interesting about Monads, namely that we can't write a general function with the type Monad m => m a -> a. In other words, we can't "extract" a value from a Monad without additional knowledge about it. So how does the do-notation syntax do {x <- [1,2,3]; return [x,x]} work? Since <- is actually just syntax sugar, just like how [1,2,3] actually means 1 : 2 : 3 : [], the above expression actually means [1,2,3] >>= (\x -> return [x,x]), which in turn evaluates to concat (map (\x -> [[x,x]]) [1,2,3])), which comes out to [1,1,2,2,3,3]. Notice how the arrow transformed into a >>= and a lambda. This uses only built-in (in the typeclass) Monad functions, so it works for any Monad in general. We can pretend to extract a value by using (>>=) :: Monad m => m a -> (a -> m b) -> m b and working with the "extracted" a inside the function we provide, like in the lambda in the list example above. However, it is impossible to actually get a value out of a Monad in a generic way, which is why the return type of >>= is m b (in the Monad)
So what is (<-) exactly? Can it be replaced entirely by using extract? Is that the best way to desugar/circumvent it? Note that the do-block <- and extract mean very different things even for types that have both Monad and Comonad instances. For instance, consider non-empty lists. They have instances of both Monad (which is very much like the usual one for lists) and Comonad (with extend/=>> applying a function to all suffixes of the list). If we write a do-block such as... import qualified Data.List.NonEmpty as N import Data.List.NonEmpty (NonEmpty(..)) import Data.Function ((&)) alternating :: NonEmpty Integer alternating = do x <- N.fromList [1..6] -x :| [x] ... the x in x <- N.fromList [1..6] stands for the elements of the non-empty list; however, this x must be used to build a new list (or, more generally, to set up a new monadic computation). That, as others have explained, reflects how do-notation is desugared. It becomes easier to see if we make the desugared code look like the original one: alternating :: NonEmpty Integer alternating = N.fromList [1..6] >>= \x -> -x :| [x] GHCi> alternating -1 :| [1,-2,2,-3,3,-4,4,-5,5,-6,6] The lines below x <- N.fromList [1..6] in the do-block amount to the body of a lambda. x <- in isolation is therefore akin to a lambda without body, which is not a meaningful thing. Another important thing to note is that x in the do-block above does not correspond to any one single Integer, but rather to all Integers in the list. That already gives away that <- does not correspond to an extraction function. (With other monads, the x might even correspond to no values at all, as in x <- Nothing or x <- []. See also Lazersmoke's answer.) On the other hand, extract does extract a single value, with no ifs or buts... GHCi> extract (N.fromList [1..6]) 1 ... however, it is really a single value: the tail of the list is discarded. If we want to use the suffixes of the list, we need extend/(=>>)... GHCi> N.fromList [1..6] =>> product =>> sum 1956 :| [1236,516,156,36,6] If we had a co-do-notation for comonads (cf. this package and the links therein), the example above might get rewritten as something in the vein of: -- codo introduces a function: x & f = f x N.fromList [1..6] & codo xs -> do ys <- product xs sum ys The statements would correspond to plain values; the bound variables (xs and ys), to comonadic values (in this case, to list suffixes). That is exactly the opposite of what we have with monadic do-blocks. All in all, as far as your question is concerned, switching to comonads just swaps which things we can't refer to outside of the context of a computation.
How efficient is the derived Eq instance in GHC?
Is there a short circuit built in to GHC's (and Haskell's in general) derived Eq instance that will fire when I compare the same instance of a data type? -- will this fire? let same = complex == complex My plan is to read in a lazy datastructure (let's say a tree), change some values and then compare the old and the new version to create a diff that will then be written back to the file. If there would be a short circuit built in then the compare step would break as soon as it finds that the new structure is referencing old values. At the same time this wouldn't read in more than necessary from the file in the first place. I know I'm not supposed to worry about references in Haskell but this seems to be a nice way to handle lazy file changes. If there is no shortcircuit builtin, would there be a way to implement this? Suggestions on different schemes welcome.
StableNames are specifically designed to solve problems like yours. Note that StableNames can only be created in the IO monad. So you have two choices: either create your objects in the IO monad, or use unsafePerformIO in your (==) implementation (which is more or less fine in this situation). But I should stress that it is possible to do this in a totally safe way (without unsafe* functions): only creation of stable names should happen in IO; after that, you may compare them in a totally pure way. E.g. data SNWrapper a = SNW !a !(StableName a) snwrap :: a -> IO (SNWrapper a) snwrap a = SNW a <$> makeStableName a instance Eq a => Eq (SNWrapper a) where (SNW a sna) (SNW b snb) = sna == snb || a == b Notice that if stable name comparison says "no", you still need to perform full value comparison to get a definitive answer. In my experience that worked pretty well when you have lots of sharing and for some reason are not willing to use other methods to indicate sharing. (Speaking of other methods, you could, for example, replace the IO monad with a State Integer monad and generate unique integers in that monad as an equivalent of "stable names".) Another trick is, if you have a recursive data structure, make the recursion go through SNWrapper. E.g. instead of data Tree a = Bin (Tree a) (Tree a) | Leaf a type WrappedTree a = SNWrapper (Tree a) use data Tree a = Bin (WrappedTree a) (WrappedTree a) | Leaf a type WrappedTree a = SNWrapper (Tree a) This way, even if short-circuiting doesn't fire at the topmost layer, it might fire somewhere in the middle and still save you some work.
There's no short-circuiting when both arguments of (==) are the same object. The derived Eq instance will do a structural comparison, and in the case of equality, of course needs to traverse the entire structure. You can build in a possible shortcut yourself using GHC.Prim.reallyUnsafePtrEquality# :: a -> a -> GHC.Prim.Int# but that will in fact fire only rarely: Prelude GHC.Base> let x = "foo" Prelude GHC.Base> I# (reallyUnsafePtrEquality# x x) 1 Prelude GHC.Base> I# (reallyUnsafePtrEquality# True True) 1 Prelude GHC.Base> I# (reallyUnsafePtrEquality# 3 3) 0 Prelude GHC.Base> I# (reallyUnsafePtrEquality# (3 :: Int) 3) 0 And if you read a structure from file, it will certainly not find it the same object as one that was already in memory. You can use rewrite rules to avoid the comparison of lexically identical objects module Equal where {-# RULES "==/same" forall x. x == x = True #-} main :: IO () main = let x = [1 :: Int .. 10] in print (x == x) which leads to $ ghc -O -ddump-rule-firings Equal.hs [1 of 1] Compiling Equal ( Equal.hs, Equal.o ) Rule fired: Class op enumFromTo Rule fired: ==/same Rule fired: Class op show the rule firing (note: it didn't fire with let x = "foo", but with user-defined types, it should).
Random-Pivot Quicksort in Haskell
Is it possible to implement a quicksort in Haskell (with RANDOM-PIVOT) that still has a simple Ord a => [a]->[a] signature? I'm starting to understand Monads, and, for now, I'm kind of interpreting monads as somethink like a 'command pattern', which works great for IO. So, I understand that a function that returns a random number should actually return a monadic value like IO, because, otherwise, it would break referential transparency. I also understand that there should be no way to 'extract' the random integer from the returned monadic value, because, otherwise, it would, again, break referential transparency. But yet, I still think that it should be possible to implement a 'pure' [a]->[a] quicksort function, even if it uses random pivot, because, it IS referential transparent. From my point of view, the random pivot is just a implementation detail, and shouldn't change the function's signature OBS: I'm not actually interested in the specific quicksort problem (so, I don't want to sound rude but I'm not looking for "use mergesort" or "random pivot doesn't increase performance in practice" kind of answers) I'm actually interested in how to implement a 'pure' function that uses 'impure' functions inside it, in cases like quicksort, where I can assure that the function actually is a pure one. Quicksort is just a good example.
You are making a false assumption that picking the pivot point is just an implementation detail. Consider a partial ordering on a set. Like a quicksort on cards where card a < card b if the face value is less but if you were to evaluate booleans: 4 spades < 4 hearts (false) 4 hearts < 4 spades (false) 4 hearts = 4 spades (false) In that case the choice of pivots would determine the final ordering of the cards. In precisely the same way for a function like a = get random integer b = a + 3 print b is determined by a. If you are randomly choosing something then your computation is or could be non deterministic.
OK, check this out. Select portions copied form the hashable package, and voodoo magic language pragmas {-# LANGUAGE FlexibleInstances, UndecidableInstances, NoMonomorphismRestriction, OverlappingInstances #-} import System.Random (mkStdGen, next, split) import Data.List (foldl') import Data.Bits (shiftL, xor) class Hashable a where hash :: a -> Int instance (Integral a) => Hashable a where hash = fromIntegral instance Hashable Char where hash = fromEnum instance (Hashable a) => Hashable [a] where hash = foldl' combine 0 . map hash -- ask the authors of the hashable package about this if interested combine h1 h2 = (h1 + h1 `shiftL` 5) `xor` h2 OK, so now we can take a list of anything Hashable and turn it into an Int. I've provided Char and Integral a instances here, more and better instances are in the hashable packge, which also allows salting and stuff. This is all just so we can make a number generator. genFromHashable = mkStdGen . hash So now the fun part. Let's write a function that takes a random number generator, a comparator function, and a list. Then we'll sort the list by consulting the generator to select a pivot, and the comparator to partition the list. qSortByGen _ _ [] = [] qSortByGen g f xs = qSortByGen g'' f l ++ mid ++ qSortByGen g''' f r where (l, mid, r) = partition (`f` pivot) xs pivot = xs !! (pivotLoc `mod` length xs) (pivotLoc, g') = next g (g'', g''') = split g' partition f = foldl' step ([],[],[]) where step (l,mid,r) x = case f x of LT -> (x:l,mid,r) EQ -> (l,x:mid,r) GT -> (l,mid,x:r) Library functions: next grabs an Int from the generator, and produces a new generator. split forks the generator into two distinct generators. My functions: partition uses f :: a -> Ordering to partition the list into three lists. If you know folds, it should be quite clear. (Note that it does not preserve the initial ordering of the elements in the sublists; it reverses them. Using a foldr could remedy this were it an issue.) qSortByGen works just like I said before: consult the generator for the pivot, partition the list, fork the generator for use in the two recursive calls, recursively sort the left and right sides, and concatenate it all together. Convenience functions are easy to compose from here qSortBy f xs = qSortByGen (genFromHashable xs) f xs qSort = qSortBy compare Notice the final function's signature. ghci> :t qSort qSort :: (Ord a, Hashable a) => [a] -> [a] The type inside the list must implement both Hashable and Ord. There's the "pure" function you were asking for, with one logical added requirement. The more general functions are less restrictive in their requirements. ghci> :t qSortBy qSortBy :: (Hashable a) => (a -> a -> Ordering) -> [a] -> [a] ghci> :t qSortByGen qSortByGen :: (System.Random.RandomGen t) => t -> (a -> a -> Ordering) -> [a] -> [a] Final notes qSort will behave exactly the same way for all inputs. The "random" pivot selection is. in fact, deterministic. But it is obscured by hashing the list and then seeding a random number generator, making it "random" enough for me. ;) qSort also only works for lists with length less than maxBound :: Int, which ghci tells me is 9,223,372,036,854,775,807. I thought there would be an issue with negative indexes, but in my ad-hoc testing I haven't run into it yet. Or, you can just live with the IO monad for "truer" randomness. qSortIO xs = do g <- getStdGen -- add getStdGen to your imports return $ qSortByGen g compare xs ghci> :t qSortIO qSortIO :: (Ord a) => [a] -> IO [a] ghci> qSortIO "Hello world" " Hdellloorw" ghci> qSort "Hello world" " Hdellloorw"
In such cases, where you know that the function is referentially transparent, but you can't proof it to the compiler, you may use the function unsafePerformIO :: IO a -> a from the module Data.Unsafe. For instance, you may use unsafePerformIO to get an initial random state and then do anything using just this state. But please notice: Don't use it if it's not really needed. And even then, think twice about it. unsafePerformIO is somewhat the root of all evil, since it's consequences can be dramatical - anything is possible from coercing different types to crashing the RTS using this function.
Haskell provides the ST monad to perform non-referentially-transparent actions with a referentially transparent result. Note that it doesn't enforce referential transparency; it just insures that potentially non-referentially-transparent temporary state can't leak out. Nothing can prevent you from returning manipulated pure input data that was rearranged in a non-reproducible way. Best is to implement the same thing in both ST and pure ways and use QuickCheck to compare them on random inputs.