I'm new to Haskell and am trying to get some code up and running on a bit of a tight schedule, which is why I'm doing something more complicated than the absolute basics. I'm using the package newsynth and would like to use the function root_of_negative_one (documentation, source). In GHCi, I run the following commands:
Prelude> import Quantum.Synthesis.Diophantine
Prelude Quantum.Synthesis.Diophantine> :set -package random
Prelude Quantum.Synthesis.Diophantine> import System.Random
Prelude Quantum.Synthesis.Diophantine System.Random> let g = getStdGen
Prelude Quantum.Synthesis.Diophantine System.Random> let x = root_of_negative_one g 5
to try to get a square root of -1 mod 5. GHCi returns:
<interactive>:7:9: error:
• No instance for (RandomGen (IO StdGen))
arising from a use of ‘root_of_negative_one’
• In the expression: root_of_negative_one g 5
In an equation for ‘x’: x = root_of_negative_one g 5
I know that root_of_negative_one needs an input of type RandomGen but I seem to have not understood the RandomGen documentation well enough to execute this. Any help is appreciated. Thanks!
root_of_negative_one needs a StdGen, but getStdGen is an IO StdGen. You need to do g <- getStdGen instead of let g = getStdGen.
Related
My goal is to get a list of N random items taken from an input list and see the result in GHCI. I decided to shuffle the input list, then take the first N elements from it (i.e. slice first elements). I am using shuffle function from random-fu module Data.Random.List.
Here's the code I currently have and at least it can be compiled
import Data.Random
import Data.Random.List
rndSelect :: [a] -> Int -> RVar [a]
rndSelect l n
= do
l' <- shuffle l;
return $ take n l'
But when I run rndSelect "abcdefg" 3 in GHCI prompt, I get the following error:
<interactive>:1:1: error:
• No instance for (Show (RVar [Char]))
arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
I think I know what it means. RVar doesn't derive Show. I guess I should modify my function so that it gets shuffled RVar[a] and then somehow take a list of the first N elements and convert it to IO action.
Here's one of my failed attempts:
rndSelect :: [a] -> Int -> IO ()
rndSelect l n
= do
l' <- shuffle l;
l'' <- take n l'
s <- runRVar l'' StdRandom
putStrLn s
I know, that it is messed up and raises errors on top of errors. I am beginner in Monads, "do" blocks and things like that in Haskell
I would be glad if someone help me to fix my approach, but if you know alternative way to achieve my goal, I will be happy to see it as well. Thank you very much!
Your rndSelect :: [a] -> Int -> RVar [a] is perfectly fine, but it should be obvious that the resulting RVar [a] can't really be shown. After all, this is a probability distribution. Such distributions “contain” in general infinitely many possible outcomes. All you can hope to do is to show samples from the distribution. Since GHCi allows you to do IO, it's easy to obtain samples right there:
*Main> sample $ rndSelect "abcdefg" 3
"def"
*Main> sample $ rndSelect "abcdefg" 3
"ecb"
*Main> sample $ rndSelect "abcdefg" 3
"fbc"
*Main> :m +Control.Monad
*Main Control.Monad> sample . replicateM 20 $ rndSelect "abcdefg" 3
["gef","adf","cga","bfd","eab","bgd","gdf","abg","egc","bda","ceb","fbd","agb","egc","acb","bga","gbd","edb","egb","egd"]
I am use org-mode blogging, I use org-babel to evaluate the code as following :
#+BEGIN_SRC haskell
import Data.Function (fix)
f :: Int -> Int
f = (+ 1)
main :: IO ()
main = do
putStrLn $ show $ f 1
#+END_SRC
#+RESULTS:
: <interactive>:9:25: Not in scope: ‘f’
I found the org-babel for haskell use infer-haskell mode to start session and eval the code. I also say the session was created, and if I don't define the function but directly putStrLn "hello" , it works.
hope anyone can fix the bug :)
In this article, Yoshinari Nomura describes a way to evaluate Haskell blocks using runhaskell via a Ruby script. I do not understand japanese, so I cannot translate the details, but the method has allowed me to run haskell blocks without having to write specifically for the interpreter.
#+BEGIN_SRC haskell
import Data.Function (fix)
f :: Int -> Int
let f = (+ 1)
main :: IO ()
main = do
putStrLn $ show $ f 1
#+END_SRC
#+RESULTS:
: 2
Org's babel mode is running the Haskell code with ghci. In ghci you are required to use let to declare functions.
I am trying to generate random number using System.MWC package. I wrote a small test code as below:
module Main where
import Data.Word(Word32)
import Control.Monad.ST as ST
import System.Random.MWC
import Data.Vector.Generic.Base
import qualified Data.Vector.Unboxed as U
test :: Word32 -> Int
test x = runST $ do
gen <- initialize (U.fromList [x] :: U.Vector Word32)
v <- uniformR (1,100) gen
return v
The problem is I am getting instance error when trying to use initialize function. This is the instance error I get:
No instance for (vector-0.9.1:Data.Vector.Generic.Base.Vector
U.Vector Word32)
arising from a use of `initialize'
Possible fix:
add an instance declaration for
(vector-0.9.1:Data.Vector.Generic.Base.Vector U.Vector Word32)
In a stmt of a 'do' block:
gen <- initialize (U.fromList [x] :: U.Vector Word32)
In the second argument of `($)', namely
`do { gen <- initialize (U.fromList [x] :: U.Vector Word32);
v <- uniformR (1, 100) gen;
return v }'
In the expression:
runST
$ do { gen <- initialize (U.fromList [x] :: U.Vector Word32);
v <- uniformR (1, 100) gen;
return v }
Failed, modules loaded: none.
I ran info in ghci to confirm that no instances are defined for Data.Vector.Generic.Base.Vector. I then checked hackage for documentation but no page exists for that package.
So, my question is where is that missing instance defined. I can load it once I know where it is defined. Importing Data.Vector.Generic.Base.Vector doesn't work. Also, mwc-random-0.13.1.1 package has a dependency on vector-0.9.1 as you can see in the error message above.
mwc-random is picking an older installed version of vector rather than the latest one. If you uninstall the older version of vector and reinstall mwc-random to pull the updated dependency of vector-0.10, then the issue resolves itself.
(Note: See the comment chain under the question for more details)
The instances are defined one by one, individually per type.
http://code.haskell.org/vector/Data/Vector/Unboxed/Base.hs
Search for #define primVector. In particular, primVector(Word32 should be the instance you're looking for.
I don't think this fixes your problem though.
What are the recommended Haskell packages for pure pseudo-random generators (uniform Doubles)?
I'm interested in a convenient API in the first place, speed would be nice too.
Maybe mwc-random?
I like the mersenne-random-pure64 package. For example you can use it like this to generate an infinite lazy stream of random doubles from a seed value:
import Data.Word (Word64)
import Data.List (unfoldr)
import System.Random.Mersenne.Pure64
randomStream :: (PureMT -> (a, PureMT)) -> PureMT -> [a]
randomStream rndstep g = unfoldr (Just . rndstep) g
toStream :: Word64 -> [Double]
toStream seed = randomStream randomDouble $ pureMT seed
main = print . take 10 $ toStream 42
using System.Random (randoms)
You can get a similar output with the builtin randoms function, which is shorter and more general (Thanks to ehird for pointing that out):
import System.Random (randoms)
import System.Random.Mersenne.Pure64 (pureMT)
main = print . take 10 $ randomdoubles where
randomdoubles :: [Double]
randomdoubles = randoms $ pureMT 42
making it an instance of MonadRandom
After reading about MonadRandom i got curious how to get PureMT working as an instance of it. Out of the box it doesn't work, because PureMT doesn't instantiate RandomGen's split function. One way to make it work is to wrap PureMT in a newtype and write a custom split instance for the RandomGen typeclass, for which there exists a default MonadRandom instance.
import Control.Monad.Random
import System.Random.Mersenne.Pure64
getTenRandomDoubles :: Rand MyPureMT [Double]
getTenRandomDoubles = getRandoms >>= return . take 10
main = print $ evalRand getTenRandomDoubles g
where g = MyPureMT $ pureMT 42
newtype MyPureMT = MyPureMT { unMyPureMT :: PureMT }
myPureMT = MyPureMT . pureMT
instance RandomGen MyPureMT where
next = nextMyPureMT
split = splitMyPureMT
splitMyPureMT :: MyPureMT -> (MyPureMT, MyPureMT)
splitMyPureMT (MyPureMT g) = (myPureMT s, myPureMT s') where
(s',g'') = randomWord64 g'
(s ,g' ) = randomWord64 g
nextMyPureMT (MyPureMT g) = (s, MyPureMT g') where
(s, g') = randomInt g
The standard System.Random has a pure interface. I would recommend wrapping it in a State g (for whatever generator g you're using) to avoid threading the state; the state function makes turning functions like next into stateful actions easy:
next :: (RandomGen g) => g -> (Int, g)
state :: (s -> (a, s)) -> State s a
state next :: (RandomGen g) => State g Int
The MonadRandom package is based on the State g interface with pre-written wrappers for the generator functions; I think it's fairly popular.
Note that you can still run actions using this pure interface on the global RNG. MonadRandom has evalRandIO for the purpose.
I think you could write an (orphan) RandomGen instance to use mwc-random with these.
A particularly nice package with a pure interface that is also suitable for cryptographic applications and yet maintains a high performance is the cprng-aes package.
It provides two interfaces: A deterministic pure one using the type classes from System.Random as well as a strong IO interface using the type classes from the Crypto-API package.
As a side note: I would generally prefer the mersenne-random packages over mwc-random. They use the original Mersenne Twister algorithm and in my benchmarks outperformed mwc-random by a large factor.
Hi i have the following code
import Data.Maybe
import Test.QuickCheck
import System.Random
rndExpr :: Gen Expr -> IO Expr
rndExpr gen = do
rnd <- newStdGen
return (generate 5 rnd gen)
But i get "not in scope "generate", why is this so?
Regards
Darren
Edit i am importing Test.QuickCheck but it still complaints about the "generate" is not in scope.
Edit 2
How would you write this function so that it would work with quickcheck version 2? I simple tried to put "unGen" where generate was with no succsess, i also installed quickcheck v 2 (cabal install QuickCheck-2.1.0.3)
I need a function with following properties stdGen->Gen Expr->Expr'
and unGen seem to give me that functionality, but as I said, my compiler cant find that function. Are there any other functions that I could use for this problem?
It seems like you are using generators from Test.QuickCheck, and generate is a function from version 1 of quickCheck. In version 2 of quickCheck things are a bit different so there is no such function. However, you atleast need to import Test.QuickCheck, and similar functionality can be gotten from unGen like this:
rundExpr gen = fmap (flip (unGen gen) 5) newStdGen
Please note that unGen is in Test.QuickCheck.Gen so you have to import that too.
generate isn't a function in System.Random. Perhaps you are looking for next?
EDIT:
Let me be clear: I don't know why you are using QuickCheck/Arbitrary for a task that Random/MonadRandom would seem to be more fitting. I'll assume you considered your options and move on.
Must you select your generator? Can't you use sample' :: Gen a -> IO a?
getVal :: IO a
getVal = sample' arbitrary
This should work for QC2.
OTOH, if you really want to use your own StdGen (or want to avoid IO) then try:
import System.Random
import Test.QuickCheck
import Test.QuickCheck.Gen
func :: StdGen -> Int
func g = unGen arbitrary g 0
This will use the StdGen named g and a count (0 here,) to generate your value. Because unGen doesn't step the generator, and the counter stepping doesn't give good randomness properties (it seems, you can try and see for yourself) you might end up wanting to wrap this with something that generates StdGens (yuck).
If you don't know what version package you are using then run:
$ ghc-pkg list | grep QuickCheck
(QuickCheck-2.1.1.1)
QuickCheck-1.2.0.1
In my setup (seen above) I have both 1 and 2, but 2 is hidden (the () means hidden) so when I use GHCi and import Test.QuickCheck it's version 1 that I get.