-
Notifications
You must be signed in to change notification settings - Fork 1
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
everything #1
base: main
Are you sure you want to change the base?
everything #1
Conversation
test/index.js
Outdated
('Constant (Constant (Constant (Number)))' + | ||
' (Constant (Constant (Number))' + | ||
' (Constant (Number)' + | ||
' (-0)))'); |
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.
😂
index.js
Outdated
//. ``` | ||
(function() { | ||
var empty; | ||
try { empty = Z.empty (A); } catch (err) { return; } |
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.
What kinds of errors can happen here? Could the attachment of ['fantasy-land/of']
be done in the Constant$bound
function with something like Z.Monoid.test
?
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.
Ah, I guess it can't be done in Constant$bound
itself, since you need it before you have a value, but couldn't it nevertheless use Z.Monoid.test(A)
?
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.
Z.Monoid.test
takes a value rather than a type representative:
> Z.Monoid.test ('abc')
true
> Z.Monoid.test (String)
false
What kinds of errors can happen here?
> Z.empty (Number)
TypeError: Monoid.methods.empty(...) is not a function
I would like to avoid try...catch
, but I can't see how to do so.
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 guess it's off topic here, but do you think it would be a good idea to add an equivalent that does work on the type rep? Then if you have some function that can take a value and obtain it's type rep, and a function that can take a type rep and determine whether it implements a typeclass, their composition is test
.
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.
That would for example allow you to avoid using the try
/catch
here; all the class membership testing can be done on the A
typerep outside of the Constant$bound
constructor, and then in Constant$bound
you just need to test whether the typerep of value
is indeed A
.
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.
Great idea! I'll investigate changes to sanctuary-type-classes which would enable this.
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.
Not 100% sure, but this approach might also yield some minor performance improvements elsewhere, by moving some checking out of the path where values are being moved around.
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.
Has an issue been posted in sanctuary-type-classes to keep track of this?
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.
Then if you have some function that can take a value and obtain [its] type rep, and a function that can take a type rep and determine whether it implements a typeclass, their composition is
test
.
fantasyland/fantasy-land#315 is the ultimate solution to this problem, I believe. Implementing that proposal is near the top of my list of Sanctuary-related tasks. :)
//. A value of type `Constant a b` always contains exactly one value, | ||
//. of type `a`. Mapping over a `Constant a b` has no effect because | ||
//. the `b -> c` function is never applied. |
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 don't really understand the Constant type, why it takes a type representative, and how that type representative relates to Constant's the type parameters. If you care to explain it to me, maybe that explanation can be added here to the introduction. :)
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.
In Haskell, we can do this:
> import Data.Functor.Constant
> pure 42 :: Constant String Int
Constant ""
We provided 42 :: Int
in “b
” position; "" :: String
materialized in “a
” position.
In JavaScript, keeping track of a
and b
in the type system is not an option so we must provide type information explicitly:
> S.of (Constant (String)) (42)
Constant (String) ('')
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.
"" :: String
materialized
Woah. o.o .... Ahh, because String is a Monoid. So Constant (Boolean)
will throw when instantiated.
Alright. That makes things clearer. I don't really see how this would be used in practice, and that's probably what most of my confusion stems from.
index.js
Outdated
//# Constant :: TypeRep a -> a -> Constant a b | ||
//. | ||
//. Constant's sole data constructor. The [type representative][] makes | ||
//. `Constant (M)` an [Applicative][]-compatible type representative if | ||
//. `M` represents some monoidal type. |
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.
Is this helpful, @Avaq?
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 read this a few times yesterday, but without being able to think up a practical use-case, I couldn't understand what it's for.
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.
@Avaq Imagine you're trying to derive:
foldMap :: Monoid m -> (a -> m) -> f a -> m
from:
traverse :: Applicative g -> (a -> g b) -> f a -> g (f b)
So you start writing:
const foldMap = ({ empty, append }) => am => fa => {
// ?
}
Now obviously the only tool you have available is traverse
, from which you're trying to derive foldMap
, so you write:
const foldMap = ({ empty, append }) => am => fa => traverse(/* ?1 */)(/* ?2 */)(/* ?3 */)
Now you're stuck with the task of producing an Applicative g
to feed into ?1
, an a -> g b
to feed into ?2
and a f a
to feed into ?3
. It just so happens we already have an fa :: f a
we received from the arguments, so that takes care of ?3
at least:
const foldMap = ({ empty, append }) => am => fa => traverse(/* ?1 */)(/* ?2 */)(fa)
Let's think about the types again:
traverse :: Applicative g -> (a -> g b) -> f a -> g (f b)
foldMap :: Monoid m -> (a -> m) -> f a -> m
we can see a few things:
- it must be the case that
g (f b) = m
g
(whatever it is) needs to have an instanceApplicative g
- this derivation must work regardless of what traversable
f
is: i.e.f b
could be any type whatsoever m
again is beyond our control: so whatever(a -> m)
the user provides tofoldMap
, it is precisely for thatm
that we must haveg (f b) = m
So, what's an applicative functor g
such that g x = m
for an arbitrary type x
and an arbitrary monoid m
? 😉
e3ab0c4
to
9221f73
Compare
index.js
Outdated
// XXX: sanctuary-show@3 only respects @@show on "objects". Fool it. | ||
Constant$bound[Symbol.toStringTag] = 'Object'; |
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.
@Avaq, here's a workaround for the issue we discussed not so long ago.
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.
Would this become a standard way of working? It seems a bit hacky.
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.
Once this is published we'll be able to define
S.lens
,S.view
,S.over
, andS.set
. :)I won't describe
Constant a b
here as the documentation should explain its use (although not necessarily its purpose). If you believe the documentation is lacking in any way, please say so.