I want to generate the sequence of
1, 1/2, 1/3, 1/4 ... *
using functional programming approach in raku, in my head it's should be look like:
(1,{1/$_} ...*)[0..5
]
but the the output is: 1,1,1,1,1 The idea is simple, but seems enough powerful for me to using to generate for other complex list and work with it.
Others things that i tried are using a lazy list to call inside other lazy list, it doesn't work either, because the output is a repetitive sequence: 1, 0.5, 1, 0.5 ...
my list = 0 ... *;
(1, {1/@list[$_]} ...*)[0..5]
See @wamba's wonderful answer for solutions to the question in your title. They showcase a wide range of applicable Raku constructs.
This answer focuses on Raku's sequence operator (...
), and the details in the body of your question, explaining what went wrong in your attempts, and explaining some working sequences.
The value of the N
th term is 1 / N
.
# Generator ignoring prior terms, incrementing an N stored in the generator:
{ 1 / ++$ } ... * # idiomatic
{ state $N; $N++; 1 / $N } ... * # longhand
# Generator extracting denominator from prior term and adding 1 to get N:
1/1, 1/2, 1/3, 1/(*.denominator+1) ... * # idiomatic (@jjmerelo++)
1/1, 1/2, 1/3, {1/(.denominator+1)} ... * # longhand (@user0721090601++)
{1/$_}
?1, 1/2, 1/3, 1/4 ... *
What is the value of the N
th term? It's 1/N
.
1, {1/$_} ...*
What is the value of the N
th term? It's 1/$_
.
$_
is a generic parameter/argument/operand analogous to the English pronoun "it".
Is it set to N
?
No.
So your generator (lambda/function) doesn't encode the sequence you're trying to reproduce.
$_
set to?Within a function, $_
is bound either to (Any)
, or to an argument passed to the function.
If a function explicitly specifies its parameters (a "parameter" specifies an argument that a function expects to receive; this is distinct from the argument that a function actually ends up getting for any given call), then $_
is bound, or not bound, per that specification.
If a function does not explicitly specify its parameters -- and yours doesn't -- then $_
is bound to the argument, if any, that is passed as part of the call of the function.
For a generator function, any value(s) passed as arguments are values of preceding terms in the sequence.
Given that your generator doesn't explicitly specify its parameters, the immediately prior term, if any, is passed and bound to $_
.
In the first call of your generator, when 1/$_
gets evaluated, the $_
is bound to the 1
from the first term. So the second term is 1/1
, i.e. 1
.
Thus the second call, producing the third term, has the same result. So you get an infinite sequence of 1
s.
{1/@list[$_+1]}
?For your last example you presumably meant:
my @list = 0 ... *;
(1, {1/@list[$_+1]} ...*)[0..5]
In this case the first call of the generator returns 1/@list[1+1]
which is 1/2
(0.5
).
So the second call is 1/@list[0.5+1]
. This specifies a fractional index into @list
, asking for the 1.5
th element. Indexes into standard Positional
s are rounded down to the nearest integer. So 1.5
is rounded down to 1
. And @list[1]
evaluates to 1
. So the value returned by the second call of the generator is back to 1
.
Thus the sequence alternates between 1
and 0.5
.
Raku passes the value of zero or more prior terms in the sequence as the arguments to the generator.
How many? Well, a generator is an ordinary Raku lambda/function. Raku uses the implicit or explicit declaration of parameters to determine how many arguments to pass.
For example, in:
{42} ... * # 42 42 42 ...
the lambda doesn't declare what parameters it has. For such functions Raku presumes a signature including $_?
, and thus passes the prior term, if any. (The above lambda ignores it.)
One could argue that, for the sequence you're aiming to generate, you don't need/want to pass any of the prior terms. Because, arguably, none of them really matter.
From this perspective all that matters is that the N
th term computes 1/N
. That is, its value is independent of the values of prior terms and just dependent on counting the number of calls.
{1/++$}
One way to compute this is something like:
{ state $N; $N++; 1/$N } ... *
The lambda ignores the previous term. The net result is just the desired 1 1/2 1/3 ...
.
(Except that you'll have to fiddle with the stringification because by default it'll use gist
which will turn the 1/3
into 0.333333
or similar.)
Or, more succinctly/idiomatically:
{ 1 / ++$ } ... *
(An anonymous $
in a statement/expression is a simultaneous declaration and use of an anonymous state scalar variable.)
As @user0721090601++ notes in a comment below, one can write a generator that makes use of the prior value:
1/1, 1/2, 1/3, {1/(.denominator+1)} ... *
For a generator that doesn't explicitly specify its parameters, Raku passes the value of the prior term in the sequence as the argument, binding it to the "it" argument $_
.
And given that there's no explicit invocant for .denominator
, Raku presumes you mean to call the method on $_
.
As @jjmerelo++ notes, an idiomatic way to express many lambdas is to use the explicit pronoun "whatever" instead of "it" (implicit or explicit) to form a WhateverCode
lambda:
1/1, 1/2, 1/3, 1/(*.denominator+1) ... *
You drop the braces for this form, which is one of its advantages. (You can also use multiple "whatevers" in a single expression rather than just one "it", another part of this construct's charm.)
This construct typically takes some getting used to; perhaps the biggest hurdle is that a *
must be combined with a "WhateverCode
able" operator/function for it to form a WhateverCode
lambda.
TIMTOWTDI
routine map
(1..*).map: 1/*
List repetition operator xx
1/++$ xx *
The cross metaoperator, X
or the zip metaoperator Z
1 X/ 1..*
1 xx * Z/ 1..*
(Control flow) control flow gather take
gather for 1..* { take 1/$_ }
(Seq) method from-loop
Seq.from-loop: { 1/++$ }
(Operators) infix ...
1, 1/(1+1/*) ... *
{1/++$} ... *
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With