Skip to content

Instantly share code, notes, and snippets.

@skids
Last active September 13, 2015 05:32
Show Gist options
  • Save skids/050f108b753ab42a215f to your computer and use it in GitHub Desktop.
Save skids/050f108b753ab42a215f to your computer and use it in GitHub Desktop.
--- a/lib/Language/functions.pod
+++ b/lib/Language/functions.pod
@@ -155,6 +155,58 @@ type:
+=head1 Conventions and Idioms
+
+While the dispatch system described above provides a lot of flexibility,
+there are some conventions that most internal functions, and those in
+many modules, will follow. These produce a consistent look and feel.
+
+=head2 Slurpy Conventions
+
+Perhaps the most important of these is the way slurpy list arguments are
+handled. Most of the time, functions will not automatically flatten
+slurpy lists. The rare exceptions are those functions that don't have a
+reasonable behavior on lists of lists.
+
+If you wish to match this look and feel, any Iterable argument must
+be broken out element-by-element into a **@ slurpy, with two nuances:
+
+=item An Iterable inside a Scalar does not count.
+=item Lists created with a C<,> at the top level count as one Iterable.
+
+This can be acheived by defining two multi candidates:
+
+ multi sub grab (**@a) { "grab $_".say for @a }
+ multi sub grab (\a) {
+ a ~~ Iterable and a.VAR !~~ Scalar ?? nextwith(|a) !! nextwith(a,)
+ }
+
+This results in the following behavior, which is known as the "single
+argument rule" or "the rule of comma" and is important to understand
+when invoking these functions:
+
+ grab (1,2); # grab 1 grab 2
+ grab ((1,2)); # grab 1 grab 2
+ grab ($(1,2)); # grab 1 2
+ grab ((1,2),3); # grab 1 2 grab 3
+ grab ((1,2),); # grab 1 2
+
+This makes user-added flattenning work consistently:
+
+ grab (flat (1,2),(3,4)); # grab 1 grab 2 grab 3 grab 4
+ grab (flat $(1,2),$(3,4)); # grab 1 2 grab 3 4
+ grab (flat (1,2)); # grab 1 grab 2
+ grab (flat $(1,2)); # grab 1 2
+
+It is worth noting that mixing binding and sigilless variables
+with these types of function requires a bit of finesse:
+
+ my $a = (1,2);
+ grab ($a); # grab 1 2
+ my $b := (1,2);
+ grab ($b); # grab 1 grab 2
+ my \c = (1,2);
+ grab (c); # grab 1 grab 2
=head1 Functions are First-Class Objects
@softmoth
Copy link

rare exceptions are those functions – it'd be nice to list names of one or two such exceptions

I would appreciate a brief word about why binding and sigilless variables behave as they do. I.e., some detail of why * ~~ Scalar is false for those two.

@cedric-vincent
Copy link

One possible sugar syntax for:

multi sub grab (\a) {
    a ~~ Iterable and a.VAR !~~ Scalar ?? nextwith(|a) !! nextwith(a,)
}

is:

my Iterable subset NonScalarIterable where { $^x.VAR !~~ Scalar }
multi sub grab (NonScalarIterable \a) { nextwith(|a) }
multi sub grab (\a) { nextwith(a,) }

It is more readable IMHO even if it isn't shorter. Actually it could be shortened if NonScalarIterable is provided by the core.

@skids
Copy link
Author

skids commented Sep 13, 2015

Well, since the use case is slurpies, maybe sub grab (***@A) could be made to automagically handle things?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment