is there a way to unwrap the following type in Haskell?
newtype Rand a = Rand(StdGen -> (a , StdGen))
I've got a function which returns this type and another one which I'd like to use the 'a' value from the returned function, but I can't figure out how to extract the value.
When you write:
newtype Rand a = Rand(StdGen -> (a , StdGen))
It's important to know what you're writing.
In this case, newtype
is equivalent to data
(the only caveat being newtype
is more efficient). So, we could alternatively write the type definition like so:
data Rand a = Rand (StdGen -> (a, StdGen))
Piece by piece:
Type constructor
| ..-- Type parameter
\|/ ..--''
' .--''
data Rand a = Rand (StdGen -> (a, StdGen))
. '---------------------'
/|\ |
| '- Wrapped data
Data constructor
First, let's look at a simpler example:
data Sum = Sum Int
Annotated:
Type constructor
|
\|/
'
data Sum = Sum Int
. '-'
/|\ '--- Wrapped data
|
Data constructor
To be clearer, we'll differentiate the type (constructor) from the (data) constructor:
data SumType = SumCon Int
Now, how would we extract the Int
held in a value x :: SumType
?
The obvious choice is pattern matching:
getSum :: SumType -> Int
getSum (SumCon n) = n
And this works. But this is a pretty common (and trivial) thing to want to do - and to make it easier, 'record syntax' was introduced. This means we can rewrite our type like so:
data SumType = SumCon { getSum :: Int }
Now we don't have to write getSum
manually any more -- the compiler will do it for us, meaning we can assume a function getSum :: SumType -> Int
exists.
Now, let's go back to Rand a
:
newtype Rand a = Rand (StdGen -> (a, StdGen))
We could either manually write:
getRand :: Rand a -> (StdGen -> (a, StdGen))
getRand (Rand f) = f
Or just let the compiler do it for us:
newtype Rand a = Rand { getRand :: StdGen -> (a, StdGen) }
When you have the data type
newtype Rand a = Rand (StdGen -> (a, StdGen))
The only way you can get an a
out of it is by supplying a StdGen
(remember, this is more or less an alias for StdGen -> (a, StdGen)
):
runRand :: Rand a -> StdGen -> (a, StdGen)
runRand (Rand f) g = f g
To make it simpler, I would recommend instead defining Rand
with record syntax:
newtype Rand a = Rand { runRand :: StdGen -> (a, StdGen) }
Where runRand
will have the same type, but now it's all defined in one line for you. If you want just the a
value, then just use fst
:
evalRand :: Rand a -> StdGen -> a
evalRand r g = fst $ runRand r g
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