0

I wish to construct a random string consisting of only alphabetical characters. This is the code I have so far:

letters :: String
letters = "abcdefghijklmnopqrstuvwxyz"

{- | Generates any lower case alpha character.
-}
lowerAlpha :: Gen Char
lowerAlpha = oneof (map return letters)

getString :: Int -> String
getString 0 = []
getString n = lowerAlpha : getString (n - 1)

getString is passed a random Int between 1 and 25. Because lowerAlpha returns a Gen Char getString wont work as it expects a Char in order to build a String. Is there a way to change a Gen String to a String? This is the line of code where the problem occurs - getString n = lowerAlpha : getString (n - 1)

5
  • If you could please make that a minimal reproducible example. It's a bit annoying when we need to guess what Gen and oneof are. Commented Sep 18, 2016 at 22:29
  • 1
    Is this a question about Quickcheck in particular, or about randomness in general? Commented Sep 18, 2016 at 22:35
  • Since Char is an instance of Enum, you can write letters = ['a'..'z'] to avoid having to type out all the lowercase letters by hand. Commented Sep 18, 2016 at 22:44
  • @Michael It's about Quickcheck. Commented Sep 19, 2016 at 0:14
  • 1
    @chepner, one should avoid oneOf here. It will surely be faster to use choose ('a', 'z'). Commented Sep 19, 2016 at 1:18

3 Answers 3

7

Is there a way to change a Gen String to a String?

No, emphatically not. For some reason, people coming from other programming languages always seem to think “they're both string-kinds of types, so surely they're convertible”. Nope! Gen String is something completely, fundamentally different from String. The latter is just a plain data value – a list of characters. But Gen String is a generator, an action that generates strings. Assuming this can be converted to a string is like assuming a cow can be converted to a milk bottle.

The correct thing is for course for getString to also have a Gen type, because generating strings is what it does.

getString :: Int -> Gen String

The question is how to implement that. Well, it's guessworking because you didn't specify what Gen is exactly, but such type constructors in Haskell are usually applicative functors. That allows you to write

getString 0 = pure []
getString n = (:) <$> lowerAlpha <*> getString (n - 1)

As gallais remarks, this can also be written shorter as

getString n = replicateM n lowerAlpha
Sign up to request clarification or add additional context in comments.

1 Comment

It might be worth mentioning replicateM.
3

Perhaps you are looking for vectorOf, i.e.:

import Test.QuickCheck

getString :: Int -> Gen String
getString n = vectorOf n lowerAlpha

To actually generate a random string you can use generate (requires the IO-monad):

main = do
  generate (getString 25) >>= putStrLn

or just from the GHCI repl:

ghci> generate (getString 25)
"siebrxrlvuuxdvhqwcfykqwdc"
ghci> generate (getString 3)
"rcv"

Comments

0

Thanks for your assistance. This is what I came up with. Works well. str <- listOf (choose ('a','z'))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.