Skip to content

Conversation

@Jason94
Copy link
Contributor

@Jason94 Jason94 commented Dec 8, 2025

Adds two small functions that just wrap update, a docstring, and an (Into x String) instance.

@shirok

@stylewarning
Copy link
Member

will wait for @shirok to comment

@stylewarning stylewarning requested a review from shirok December 8, 2025 05:48
Copy link
Collaborator

@shirok shirok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious how it will fit into the broader plan of mapping and collection interface.

Also, tests would be nice, even the trivial ones.

(Tuple (HashMap newnode) aux)))

(inline)
(declare modify (Hash :k => HashMap :k :v -> :k -> (:v -> :v) -> Tuple (HashMap :k :v) (Optional :v)))
Copy link
Collaborator

@shirok shirok Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the code is written to return Tuple (Optional (HashMap :k :v)) (Optional :v).

If this pattern is useful, we want to have it in the mapping protocol. I wonder, though, if it is useful to return (Optional (HashMap :k :v))---as update is the most general protocol, we want modify to be a convenience utility, as easy to use as possible. Do the caller wants to know whether the map is modified or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does compile, if that's what you're concerned about. The overall modify function just returns the HashMap, and returns an optional modified value (None in case the the key was missing). I included this version that returns the (Optional :v) because sometimes it is nice to do a modify-and-get all at once. But I could be convinced to get rid of this one, and just make modify_ be modify. I'm sure that's the most common of any of these "specialized version of update" use cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, and feel free to chime in here: #1329. It would be great to get all of the good discussion on the map interface together.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, my bad. I confused update protocol even I wrote that. Please disregard Optional thing.

(Tuple (Some result) (Some result))))))))

(inline)
(declare modify_ (Hash :k => HashMap :k :v -> :k -> (:v -> :v) -> HashMap :k :v))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: The code returns (Optional (HashMap :k :v)).

Another question is the naming convention. If we'll have modify and modify_, I'd like to have the (mostly) consistent interface for other foo and foo_ variations. If this variations fit into the broader collection framework, I'm ok with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? It's compiling on my machine, and I'm using it in a project. Maybe our versions of the repo are out of sync, or something? In any case, I just added some tests, so maybe take a look at those?

Yeah, the _ suffix convention is something I like using for simpler versions of functions that have a less expressive (but sometimes more useful) type signature. I don't know if there's much of that pattern in the standard library, though. Alternatively, this one could be modify and the other one could be modify-get or something.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as the convention of _ will be established, I'm fine with it.

(define-instance (Hash :k => Monoid (HashMap :k :v))
(define mempty Empty))

(define-instance ((Hash :k) (Into :k String) (Into :v String) => Into (HashMap :k :v) String)
Copy link
Collaborator

@shirok shirok Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Into * String can be one of two things: Convert a thing into a string representation (obtaining external representation), or convert a sequence to a character sequence. Example of the latter is to convert a list of characters or a vector of characters into a string. I think those two needs to have distinct names.

My instinct is to keep Into * String as a sequence-seqence conversion (e.g. so it can be parallel with Into * List or Into * Seq etc., and have a separate protocol to get an external representation, much like Haskell's show.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree about Show. I think that's the long term plan. (#1641). And I agree this would be more suited to a "Show" instance than a conversion instance.

We could put this in for now and change it to Show later, when it gets added, or wait to add this (or something like it) then.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm for having intermediate plan before we have full show protocol. In that case, how about having a different name (e.g. to-string or stringify) so that it will be easier to move once show is in place?

I'm afraid that once we conflate into, it would be cumbersome to discern different protocols later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this. Maybe even just call it show-*.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just pushed up a commit simply calling it show. Eventually when we do get a show typeclass, that should make it easy for any code that uses it to convert.

#:remove
#:update
#:modify
#:modify_
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a big fan of this convention. It's vague ("the simpler/reduced call"). I don't feel the need to be a stickler about it though.

@stylewarning stylewarning requested a review from shirok December 8, 2025 22:23
@stylewarning
Copy link
Member

@shirok I reset your review since you just commented.

I'm not a huge fan of the _ convention, but I'm happy to make it one if we can "define" it sufficiently well. I want the more useful functions to generally be the ones with more normal names. Is there something we can agree on here that aligns with that? I almost think modify should just return the map (if I were to "guess" the type of such a function).

I'm open to ideas.

@shirok
Copy link
Collaborator

shirok commented Dec 8, 2025

@stylewarning Yes, my hunch is it's more natrual to expect modify :: HashMap :k :v -> :k -> (:v -> :v) -> HashMap :k :v. A variation may be to take the "default" value when the key doesn't exist. With the default value, it is easy to write the typical patterns such as "push a value into the entry--if the entry didn't exist, assume ()" or "increment the associated value--if the entry didn't exist, assume 0". In CL, I'd certainly add &optional default.

I don't see much use case in obtaining the new value; if I can spend some more cycles I can lookup again with the key, or I can fall back to the general update. But if it makes some common patterns easier to write, I don't oppose to have it, but with more descriptive name.

@Jason94
Copy link
Contributor Author

Jason94 commented Dec 8, 2025

@shirok I reset your review since you just commented.

I'm not a huge fan of the _ convention, but I'm happy to make it one if we can "define" it sufficiently well. I want the more useful functions to generally be the ones with more normal names. Is there something we can agree on here that aligns with that? I almost think modify should just return the map (if I were to "guess" the type of such a function).

I'm open to ideas.

That's reasonable. In that case, I think modify and modify-get would be fine.

@stylewarning
Copy link
Member

(tests fail because of a bug that's been fixed on main; just rebase)

Adds two small functions, a docstring, and an (Into x String) instance
@Jason94 Jason94 force-pushed the hashmap-small-additions branch from 450c6ad to 71cf7af Compare December 11, 2025 02:18
modify_ -> modify, modify->modify-get
@Jason94 Jason94 force-pushed the hashmap-small-additions branch from 71cf7af to dfbc664 Compare December 11, 2025 02:28
@Jason94
Copy link
Contributor Author

Jason94 commented Dec 11, 2025

(tests fail because of a bug that's been fixed on main; just rebase)

Hmm. I rebased but I'm still getting the SBCL failures. It doesn't look like my branch is behind main.

@stylewarning
Copy link
Member

lol, this is the outdated quicklisp issue and named-readtables...

will fix

@stylewarning stylewarning merged commit 7d463c8 into coalton-lang:main Dec 11, 2025
33 of 50 checks passed
@Jason94 Jason94 deleted the hashmap-small-additions branch December 11, 2025 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants