-
Notifications
You must be signed in to change notification settings - Fork 21
Explain why Ref functions return Effect (Ref s)
rather than Ref s
#30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bd71721
bff52e3
b520891
1590dd5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,40 @@ | |
-- | | ||
-- | _Note_: `Control.Monad.ST` provides a _safe_ alternative to `Ref` when | ||
-- | mutation is restricted to a local scope. | ||
-- | | ||
-- | You'll notice that all of the functions that operate on a `Ref` | ||
-- | (e.g. `new`, `modify`, `modify_`, `read`) return an `Effect (Ref s)` | ||
-- | and not a `Ref s`. Here's what would happen if the `Ref s` was not | ||
-- | wrapped in an `Effect`: | ||
-- | 1. In some situations, one could violate referential transparency. | ||
-- | 2. One can violate the type system by giving a `Ref` a polymorphic type | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After reflecting on this a bit more, I think this particular point is specific to |
||
-- | and then specializing it after the fact. | ||
-- | | ||
-- | In regards to the first, consider the below example: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the topic of why using Refs is effectful in general, I think it will probably be more persuasive to use a simpler example where a Ref is created, read from, written to, and then read from again: that's likely to be easier to understand than this example, which is a bit more subtle. |
||
-- | ``` | ||
-- | let | ||
-- | x = Ref.new “hi” | ||
-- | first = Tuple x x | ||
-- | second = Tuple (Ref.new "hi") (Ref.new "hi") | ||
-- | ``` | ||
-- | In the above code, `first` holds the same reference twice whereas `second` | ||
-- | holds two different references. Thus, it invalidates referential | ||
-- | transparency. If `first` was referentially transparent to `second`, | ||
-- | then `first` would hold two separate references just like `second`. | ||
-- | By making `Ref.new` return an `Effect`, we return an _action_. Each time | ||
-- | this action is called, it will create a new separate reference that is | ||
-- | initialized to the given value. | ||
-- | | ||
-- | In regards to the second, consider the below example: | ||
-- | ``` | ||
-- | let | ||
-- | ref :: forall a. Ref (Maybe a) | ||
-- | ref = Ref.new Nothing | ||
-- | in | ||
-- | Tuple (ref :: Ref (Maybe Int)) (ref :: Ref (Maybe String)) | ||
-- | ``` | ||
-- | The Tuple stores the same reference twice, but its type is `Maybe Int` in | ||
-- | one situation and `Maybe String` in another. | ||
module Effect.Ref | ||
( Ref | ||
, new | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think putting it this way downplays the importance of Effect to retain referential transparency here; I'd argue that a Ref which could be read or written outside of Effect would end up violating referential transparency in almost all situations, since every time you write a new value to a ref, you change the result of reading from it. I also think we could do more to explain what referential transparency is, as if the reader isn't already familiar with the term, these docs probably won't make a lot of sense (and if they are familiar with it, they likely understand why reading or writing a Ref is effecful already anyway).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So... change the wording to "In all situations, one will violate referential transparency" ?
Odd. Usually you want docs to explain less and have readers look up terms elsewhere. Why the change here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, that’s not quite accurate either - it’s definitely possible that a Ref is initialised and then never written to, in which case all of the reads would return the same value and you wouldn’t observe a violation.
I want docs to only address things that are directly relevant to the topic at hand; in this case, referential transparency is directly relevant to why refs are effectful. I also expect that it only needs a sentence or two; if it needed more than that, I’d agree that it should go elsewhere. If you can point to an example where you think I’m being inconsistent I’m happy to reconsider.