[GHC] #10160: GHCi :sprint has odd/unhelpful behavior for values defined within the REPL
GHC
ghc-devs at haskell.org
Sun Mar 15 06:27:17 UTC 2015
#10160: GHCi :sprint has odd/unhelpful behavior for values defined within the REPL
-------------------------------------+-------------------------------------
Reporter: bitemyapp | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: GHCi | Version: 7.8.4
Resolution: | Keywords: :sprint
Operating System: Unknown/Multiple | thunk evaluation non-strictness
Type of failure: Incorrect result | laziness runtime ghci repl
at runtime | Architecture:
Blocked By: | Unknown/Multiple
Related Tickets: | Test Case:
| Blocking:
| Differential Revisions:
-------------------------------------+-------------------------------------
Description changed by bitemyapp:
Old description:
> Wanted to use :sprint to help learners visualise thunk evaluation
> behavior in their data. Ran into some behaviors that a few people I
> checked with didn't have a good explanation for. I couldn't find anything
> in the user guide to explain this. I don't think it technically violates
> Haskell Report requirements, but it makes :sprint considerably less
> useful if you're teaching somebody non-strictness.
>
> Examples with code in the REPL:
>
> {{{
> Prelude> let x = [1, 2, 3]
> Prelude> :sprint x
> x = _
> Prelude> :t x
> x :: Num t => [t]
> -- this makes sense so far.
>
> Prelude> let x = [1, 2, 3 :: Integer]
> Prelude> :sprint x
> x = [1,2,3]
> -- errr, what?
>
> Prelude> let x = Just (1 :: Integer)
> Prelude> :sprint x
> x = Just 1
>
> Prelude> let just = Just
> Prelude> let x = just (1 :: Integer)
> Prelude> :sprint x
> x = _
>
> Prelude> let x = Just (undefined :: Integer)
> Prelude> :sprint x
> x = Just _
>
> Prelude> let x = just (undefined :: Integer)
> Prelude> :sprint x
> x = _
>
> Prelude> let x = [1, 2, 3 :: Integer]
> Prelude> let y = x
> Prelude> :sprint y
> y = [1,2,3]
>
> Prelude> let x = 1 : 2 : (3 :: Integer) : []
> Prelude> :sprint x
> x = [1,2,3]
> Prelude> let x = [1] ++ [2] ++ [(3 :: Integer)]
> Prelude> :sprint x
> x = _
>
> Prelude> let y = (:)
> Prelude> let x = 1 `y` (2 `y` ((3 :: Integer) `y` []))
> Prelude> :sprint x
> x = _
> Prelude> x
> [1,2,3]
> Prelude> :sprint x
> x = [1,2,3]
> }}}
>
> So the behavior here seems to be:
>
> Constructors used directly in the construction of data and are not passed
> functions (including polymorphic vals awaiting concrete
> instances)/bottoms are immediately evaluated
>
> Example, but with loading data from a file:
>
> Contents of the file:
>
> {{{
> x :: Num a => [a]
> x = [1, 2, 3]
> }}}
>
> GHCi session:
>
> {{{
> Prelude> :t x
> x :: Num a => [a]
>
> Prelude> :sprint x
> x = _
>
> Prelude> x
> [1,2,3]
>
> Prelude> :sprint x
> x = _
> }}}
>
> Then when x is loaded from a file, but has a different type:
>
> {{{
> Prelude> :t x
> x :: [Integer]
> Prelude> :sprint x
> x = _
> Prelude> head x
> 1
> Prelude> :sprint x
> x = [1,2,3]
> }}}
>
> Now, this is a bit confusing. Earlier I was able to get :sprint to return
> [1, _, _] when I evaluated head x, but a couple hours later when I went
> to write this ticket, I couldn't reproduce that behavior.
>
> Is there documentation that explains:
>
> 1. Why data is shown as having been evaluated at time of declaration
> (seemingly) by :sprint when it's defined in the GHCi
>
> 2. Why declaring code in GHCi and loading it from a file behaves
> differently with :sprint (I considered let expression in the implicit
> GHCi do-block...couldn't find anything to explain this)
>
> 3. Why evaluating 'head x' forces the other values as well
>
> Are any of these behaviors a bug? If not, are they documented anywhere?
> Is the "eager" treatment of constructors in GHCi a performance thing?
> That seems strange given I didn't have -fobject-code turned on.
>
> :sprint not demonstrating semantics that match what I expect from a non-
> strict language hinders its utility as a teaching tool and means the only
> robust option for learners that I can find is testing evaluation with
> bottom values.
>
> {{{
> -- So that you know i picked "7.8.4" as the version consciously
>
> [callen at atlantis ~/Work/fpbook]$ ghc --version
> The Glorious Glasgow Haskell Compilation System, version 7.8.4
>
> [callen at atlantis ~/Work/fpbook]$ ghci --version
> The Glorious Glasgow Haskell Compilation System, version 7.8.4
> }}}
New description:
Wanted to use :sprint to help learners visualise thunk evaluation behavior
in their data. Ran into some behaviors that a few people I checked with
didn't have a good explanation for. I couldn't find anything in the user
guide to explain this. I don't think it technically violates Haskell
Report requirements, but it makes :sprint considerably less useful if
you're teaching somebody non-strictness.
Examples with code in the REPL:
{{{
Prelude> let x = [1, 2, 3 :: Integer]
Prelude> :sprint x
x = [1,2,3]
-- errr, what?
Prelude> let x = Just (1 :: Integer)
Prelude> :sprint x
x = Just 1
Prelude> let just = Just
Prelude> let x = just (1 :: Integer)
Prelude> :sprint x
x = _
Prelude> let x = Just (undefined :: Integer)
Prelude> :sprint x
x = Just _
Prelude> let x = just (undefined :: Integer)
Prelude> :sprint x
x = _
Prelude> let x = [1, 2, 3 :: Integer]
Prelude> let y = x
Prelude> :sprint y
y = [1,2,3]
Prelude> let x = 1 : 2 : (3 :: Integer) : []
Prelude> :sprint x
x = [1,2,3]
Prelude> let x = [1] ++ [2] ++ [(3 :: Integer)]
Prelude> :sprint x
x = _
Prelude> let y = (:)
Prelude> let x = 1 `y` (2 `y` ((3 :: Integer) `y` []))
Prelude> :sprint x
x = _
Prelude> x
[1,2,3]
Prelude> :sprint x
x = [1,2,3]
}}}
So the behavior here seems to be:
Constructors used directly in the construction of data and are not passed
functions (including polymorphic vals awaiting concrete instances)/bottoms
are immediately evaluated
Example, but with loading data from a file:
Contents of the file:
{{{
x :: Num a => [a]
x = [1, 2, 3]
}}}
GHCi session:
{{{
Prelude> :t x
x :: Num a => [a]
Prelude> :sprint x
x = _
Prelude> x
[1,2,3]
Prelude> :sprint x
x = _
}}}
Then when x is loaded from a file, but has a different type:
{{{
Prelude> :t x
x :: [Integer]
Prelude> :sprint x
x = _
Prelude> head x
1
Prelude> :sprint x
x = [1,2,3]
}}}
Now, this is a bit confusing. Earlier I was able to get :sprint to return
[1, _, _] when I evaluated head x, but a couple hours later when I went to
write this ticket, I couldn't reproduce that behavior.
Is there documentation that explains:
1. Why data is shown as having been evaluated at time of declaration
(seemingly) by :sprint when it's defined in the GHCi
2. Why declaring code in GHCi and loading it from a file behaves
differently with :sprint (I considered let expression in the implicit GHCi
do-block...couldn't find anything to explain this)
3. Why evaluating 'head x' forces the other values as well
Are any of these behaviors a bug? If not, are they documented anywhere? Is
the "eager" treatment of constructors in GHCi a performance thing? That
seems strange given I didn't have -fobject-code turned on.
:sprint not demonstrating semantics that match what I expect from a non-
strict language hinders its utility as a teaching tool and means the only
robust option for learners that I can find is testing evaluation with
bottom values.
{{{
-- So that you know i picked "7.8.4" as the version consciously
[callen at atlantis ~/Work/fpbook]$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.8.4
[callen at atlantis ~/Work/fpbook]$ ghci --version
The Glorious Glasgow Haskell Compilation System, version 7.8.4
}}}
--
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/10160#comment:2>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list