Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#2470 closed bug (invalid)

read for StdGen fails for arbitrary string

Reported by: guest Owned by:
Priority: normal Milestone:
Component: libraries/random Version: 6.8.3
Keywords: StdGen read Cc:
Operating System: Windows Architecture: x86
Type of failure: Difficulty: Unknown
Test Case: Blocked By:
Blocking: Related Tickets:

Description

According to the docs for StdGen?:

"In addition, read may be used to map an arbitrary string (not necessarily one produced by show) onto a value of type StdGen?. In general, the read instance of StdGen? has the following properties:

  • It guarantees to succeed on any string.
  • It guarantees to consume only a finite portion of the string.
  • Different argument strings are likely to result in different results."

Here's what happens on my system:

C:\odm\ghc\lib>ghci
GHCi, version 6.8.3: http://www.haskell.org/ghc/ :? for help
Loading package base ... linking ... done.
Prelude> :mod +System.Random
Prelude System.Random> (read "tasty tofu") :: StdGen?
Loading package old-locale-1.0.0.0 ... linking ... done.
Loading package old-time-1.0.0.0 ... linking ... done.
Loading package random-1.0.0.0 ... linking ... done.
* Exception: Prelude.read: no parse
Prelude System.Random>

You can contact me at orielmaxime@… if you need more information.

Attachments (1)

cantreadstdgen.txt (445 bytes) - added by guest 6 years ago.

Download all attachments as: .zip

Change History (7)

Changed 6 years ago by guest

comment:1 Changed 6 years ago by guest

With further thought, I wonder if I misunderstand the specification. From reading the code, it looks like the read instance is using the first 6 characters to construct the StdGen? result. However, because the rest of the string is "left over" and unprocessed, the read call fails whenever there are more than 6 characters in the passed string.

Two notes: (1) The number 6 is undocumented, making the behavior of read incompehensible without examining the code; (2) it's unclear how this specification interacts with compound structures, like the derived instance of read :: String -> (StdGen?,StdGen?). What would we expect read "(longword,longerword,longestword)" :: (StdGen?,StdGen?) to do? How do we know which commas mean what?

If whoever looks at this decides this is an enhancement rather than a bug, I won't be too terribly hurt. Again, you can contact me at orielmaxime@…. Exposing stdFromString (perhaps with a different name) might make everything cleaner.

comment:2 follow-up: Changed 6 years ago by igloo

  • Difficulty set to Unknown
  • Resolution set to invalid
  • Status changed from new to closed

Strings that are the result of showing a StdGen? work fine as part of structures:

Prelude System.Random> let x = (mkStdGen 100, mkStdGen 200)
Prelude System.Random> x
(101 1,201 1)
Prelude System.Random> let y = show x
Prelude System.Random> y
"(101 1,201 1)"
Prelude System.Random> let z = read y :: (StdGen,StdGen)
Prelude System.Random> z
(101 1,201 1)
Prelude System.Random> 

For reading a random string you can use reads to avoid the exception.

We've discussed this before, although I can't find the ticket now (it might have been on a mailing list or something), and concluded that given the "finite portion" requirement the current behaviour is the best.

comment:3 Changed 6 years ago by guest

igloo: would it be appropriate to document the "read 6 characters"? Just a final thought. At a minimum, my interpretation of the phrase "using different strings is likely to result in different generators" is strongly violated by a dependency on the first six characters, unless that's documented.

No worries either way.

comment:4 Changed 6 years ago by Isaac Dupree

IMHO it would be appropriate to specify in the documentation that (read::String->StdGen?) is only guaranteed to work on the result of (show::StdGen?->String). The "read 6 characters" can be mentioned as an implementation detail. (Then it's just like all other read/show pairs: it works fine in tuples.) That leaves us free to / forces us to come up with a more proper suite of functions for initializing a generator (for example, taking all the bits in a finite list into account, initializing from an Int, from an Integer, etc.)

-Isaac

comment:5 in reply to: ↑ 2 Changed 6 years ago by ross

Replying to igloo:

Strings that are the result of showing a StdGen? work fine as part of structures [...]

For reading a random string you can use reads to avoid the exception.

The description quoted in the bug report, including "It guarantees to succeed on any string" is in the Haskell 98 Report. Not implementing that would be a bug, wouldn't it?

comment:6 Changed 6 years ago by Isaac Dupree

The Haskell 98 report is buggy; that behavior is unimplementable when applying (read::String->StdGen) to an infinite list. Actually, no, that's not quite right. (readsPrec::Int->ReadS StdGen) == (readsPrec::Int->String->[(StdGen,String)]). So readsPrec could be defined to read only a finite amount of the string, and unconditionally return [(result,"")] so that "read" always succeeded. But that breaks the read/show identities (e.g. (read.show)::[StdGen]->[StdGen] would break), and in general breaks the expected behavior for the reads functions, so I don't think it's worth it to pretend the standard isn't broken there.

-Isaac

Note: See TracTickets for help on using tickets.