Ruby has a strange operator, ..
, called flip-flop (not to be confused with the range operator, which looks the same). Used in a loop, flip-flop takes two conditions as operands and will return false
until the first operand is truthy, then return true
until the second operand is truthy, whereupon it returns true
one more time and restarts the cycle with false
.
0.upto 10 do |i|
if (i==2)..(i==8)
puts i
end
end
# Prints 2, 3, 4, 5, 6, 7, and 8
Your task is to implement a higher-order function (or something equivalent in your language) that behaves like flip-flop. It must take two predicate functions as arguments and return a new function that takes an argument and returns falsey until the first predicate returns true
given the argument, continues to return true
until the second predicate returns true
, whereupon the flip-flop returns true
one more time (think of it like an inclusive range) and thereafter returns false
, until the first predicate returns true
again and so on.
Below is an example of such a function called make_flip_flop
, which takes two predicate lambdas and returns a new lambda, flip_flop
, to be used in the following loop.
flip_flop = make_flip_flop(->i{ i==2 }, ->{ i == 8 })
0.upto 10 do |i|
if flip_flop.(i)
puts i
end
end
# Prints 2, 3, 4, 5, 6, 7, and 8
Here's another example with a different set of predicates:
flip_flop = make_flip_flop(->i{ i % 5 == 0 }, ->i{ i % 5 == 2 })
0.upto 10 do |i|
if flip_flop.(i)
puts i
end
end
# Prints 0, 1, 2, 5, 6, 7, and 10
Rules
Please include a brief example or description of how your solution works.
Since not all languages have first-class functions, the definition of "predicate" is loose. You could take the names of previously-defined functions to be called or a string to be eval'd, for example. Your solution may not, however, just take primitive values like
true
andfalse
. It must be your language’s equivalent of a higher-order function.Your predicate functions should take at least one argument, of any type that's convenient, as long as it's reasonable. (A predicate that only takes the specific value
1
is not reasonable, for example.)Built-ins are allowed, but only if they fit the spec (it must be a function or similar, etc.). You can’t post Ruby, 2 bytes,
..
.Default I/O rules apply, standard rules apply, and standard loopholes are forbidden.
This is code golf. Shortest answer in bytes wins.
19 Answers 19
JavaScript (ES6), 26 bytes
Expects [ first_predicate, second_predicate ]
, where both predicates are functions taking a single parameter.
Returns a flip-flop function which itself returns either 0 or 1.
(p,k=0)=>v=>k|(k^=p[k](v))
Commented
( // flip-flop generator taking:
p, // p[] = pair of predicate functions
k = 0 // k = flip-flop status, initialized to 0
) => //
v => // anonymous function taking a parameter v
k | ( // always return 1 if k is already set
// (because we must still return 1 when the 2nd
// predicate is triggered)
k ^= p[k](v) // toggle k if the result of p[k](v) is true
) //
Python, 59 bytes
lambda a,b:lambda x,t={0}:t.add((o:=t.pop()|a(x))>b(x))or o
Anonymous function returning an anonymous function that keeps state in a mutable initialiser.
-
\$\begingroup\$ Ah, so the default value in the inner lambda is per-outer lambda? Nice! \$\endgroup\$Neil– Neil2022年10月14日 19:57:30 +00:00Commented Oct 14, 2022 at 19:57
-
\$\begingroup\$ @Neil. Pretty sure the entire inner lambda is per outer lambda: The inner function definition is executed each time the outer lambda is called and creates a new function object with its own closure and default values. \$\endgroup\$loopy walt– loopy walt2022年10月14日 20:38:01 +00:00Commented Oct 14, 2022 at 20:38
C (clang), 43 bytes
Reusable form as proposed by AZTECCO
#define f(x,a,b)static m;m|(m^=m?x b:x a)&&
C (clang), (削除) 41 (削除ここまで) 40 bytes
-1 byte thanks to ceilingcat!
t;f(a(),b(),i,*r){*r=t|(t^=(t?b:a)(i));}
-
1\$\begingroup\$ A perfect example to demonstrate why implicit int is bad. :) \$\endgroup\$corvus_192– corvus_1922022年10月15日 14:43:47 +00:00Commented Oct 15, 2022 at 14:43
-
\$\begingroup\$ I don't think this is valid answer, f isn't reusable since t isn't initialized prior usage, moreover I honestly don't really like how the function, variables and for loop mix up, however there's not much you can do in c to achieve the task \$\endgroup\$AZTECCO– AZTECCO2022年10月15日 21:06:32 +00:00Commented Oct 15, 2022 at 21:06
-
\$\begingroup\$ yeah, I had the same discussion with @solid.py. I guess this answer is a bit of a flop :-) \$\endgroup\$jdt– jdt2022年10月15日 21:29:16 +00:00Commented Oct 15, 2022 at 21:29
-
\$\begingroup\$ Maybe a bit stretchy but can be valuable. Obviously the t thing has to be addressed in some ways.. Maybe cut it off and just use r pre-initialized, Idk if it would be valid but seems reasonable to me \$\endgroup\$AZTECCO– AZTECCO2022年10月15日 22:27:18 +00:00Commented Oct 15, 2022 at 22:27
-
\$\begingroup\$ Not sure is acceptable but at least it should be reusable Try it online! \$\endgroup\$AZTECCO– AZTECCO2022年10月16日 11:57:10 +00:00Commented Oct 16, 2022 at 11:57
Raku, 18 bytes
->\f,\g{&{f ff g}}
Raku has a built-in operator ff
that does exactly what's asked for. My answer is mostly just setting up the functional plumbing around it.
-> \f, \g { ... }
is an anonymous subroutine taking two arguments.&{ ... }
is the anonymous subroutine the top-level subroutine returns. Not having an explicit signature, it takes its argument in the topic variable$_
, which the flip-flop operator implicitly checks against.f ff g
returns false until the topic variable smartmatches againstf
, that is,$_ ~~ f
, then keeps returning true until$_ ~~ g
. Sincef
andg
are functions, those smartmatches are equivalent tof($_)
andg($_)
.
Factor, 33 bytes
[ '[ _ _ bi on t get swap off ] ]
Expects the false-making predicate first and the true-making predicate second.
[ ... ]
A quotation (anonymous function)...'[ ... ]
...that creates a quotation (anonymous function)._ _
Slot the predicates into the holes.bi
Call both predicates on the inner quotation's input value (integer).on
Here's where it gets tricky. In Factor, you can use any value as a variable (key) to store something. So what I am doing here is using the result of the true-making predicate to store the valuet
. It's a little strange to use a canonical boolean value to store a possibly different boolean value, but this is code golf. It's not supposed to make sense, it's just supposed to be short.t get
Get the value that is stored int
. This is the result that will be returned from the quotation. This must be done after storing the result of the true-making predicate but before storing the result of the false-making predicate in order to get the 'inclusive' behavior we are looking for.swap
Bring the result of the false-making predicate to the top of the stack.off
Storef
in the result of the false-making predicate.
R, 54 bytes
{x=F;function(f,g)function(y){x<<-(z=x|f(y))&!g(y);z}}
(or 52 bytes using a global variable to save the current state)
R, 37 bytes (non-competing)
{x=F;function(f,g){x<<-(z=x|f)&!g;z}}
Doesn't fit the written spec of the challenge (the function %..%
returns truthy/falsy, rather than a function), but it seems to very well mimic the described behaviour of Ruby's ..
.
Usage example (to mimic the Ruby example in the challenge):
for(i in 1:20){
if((i==2)%..%(i==8))print(i)
}
-
\$\begingroup\$ @Jordan - please could you have a look at the 37-byte answer above, which doesn't return a function but seems to me to very well mimic the Ruby
..
flip-floperator, and let me know if this is acceptable? Edit: re-reading the spec, I see this isn't acceptable... \$\endgroup\$Dominic van Essen– Dominic van Essen2022年10月15日 08:40:50 +00:00Commented Oct 15, 2022 at 8:40
Japt, (削除) 29 (削除ここまで) 13 bytes
Ï{T|(T^=YgXgT
Defines a function which accepts an array of predicates as its input, and returns the flip-flop function. Theoretically should work on strings, numbers, or arrays as the input for the predicate, but I've only tested with numbers.
Ï{T|(T^=YgXgT
# Initialize T = 0
Ï # Define a function with argument X (an array of predicates):
{ # Return a function with argument Y:
T # Current value of T
| # Bitwise OR
(T^= # T XOR-equals the following:
XgT # Get the function in X at index T
Yg # Apply it to Y
A 16 byte alternative doesn't use a global variable, so could be used to define multiple flip flops.
-
1\$\begingroup\$ I think a global variable is fine for code golf, and defining a function is fine. \$\endgroup\$Jordan– Jordan2022年10月14日 19:12:58 +00:00Commented Oct 14, 2022 at 19:12
-
\$\begingroup\$ @Jordan I kept the global variable, but I found a shorter answer which is more in line with being a
make_flip_flop
function \$\endgroup\$Kamil Drakari– Kamil Drakari2022年10月14日 19:23:31 +00:00Commented Oct 14, 2022 at 19:23
Python, 76 bytes
-1 byte
thanks to py3_and_c_programmer
Takes as input an element i
, two lambda functions a
and b
while using a global variable t
to toggle between the true
& false
cycles.
def f(i,a,b):
global t
if~t&a(i):t=1
if t&b(i):t=0;return 1
return t
t=0
-
\$\begingroup\$ In Python, you don't really need the
;
aftert=0
\$\endgroup\$Rhaixer– Rhaixer2022年10月15日 04:09:33 +00:00Commented Oct 15, 2022 at 4:09 -
\$\begingroup\$ @py3_and_c_programmer Well it was an erroneous copy-paste but thanks for pointing out. \$\endgroup\$solid.py– solid.py2022年10月15日 07:42:46 +00:00Commented Oct 15, 2022 at 7:42
Husk, (削除) 12 (削除ここまで) 10 bytes
%2ṁ§≠2o0←ḣ
%2ṁ§≠2o0←ḣ # 2-argument function,
# which yields a partially-applied function
# requiring 1 further argument:
ḣ # 1..further argument
ṁ # map over this and return sum
§≠ # absolute differences between
2 # function arg2 applied to each element, and
o0 # function arg1 applied to
← # each element plus 1;
%2 # modulo 2.
Example usage f123ḣ20
f # filter
ḣ20 # 1..20
# keeping only truthy results of
1 # function returned by function on line 1
# called with arguments:
23 # functions on line 2 and line 3
Rust, 40 bytes
|f|{let mut t=0;move|x|t|{t^=f[t](x);t}}
An expression compatible with fn([fn(T)->usize; 2])->impl Fn(T)->usize
for any T
. (Yes I know impl Trait
can't be used as a return type for fn
pointers)
-
1\$\begingroup\$ Right, I updated the code but forgot to change the count & link. \$\endgroup\$corvus_192– corvus_1922022年10月15日 17:13:44 +00:00Commented Oct 15, 2022 at 17:13
C++ (clang), 64 bytes
[t=0](auto p){return[=](auto x)mutable{return t|(t^=p[t](x));};}
Port of @Arnauld's JavaScript answer.
Instead of t
being a default parameter, it's captured and initialized to 0. The function returns a mutable lambda which captures this t
by value along with the predicates container.
This other lambda (the closure) does the heavy lifting, it's declared mutable because it's member t
will alternate between the values 0 and 1.
We could save a byte by making the predicates take an int x
but it would no longer be generic.
-
1\$\begingroup\$ Capture default.. I love that! \$\endgroup\$AZTECCO– AZTECCO2022年10月15日 20:59:32 +00:00Commented Oct 15, 2022 at 20:59
-
\$\begingroup\$ Hm, this feels like you cheated a bit, since you need to explicitly specify the template parameter type when using this lambda for it to work correctly. \$\endgroup\$G. Sliepen– G. Sliepen2022年10月17日 08:21:52 +00:00Commented Oct 17, 2022 at 8:21
-
1\$\begingroup\$ @G.Sliepen, it's only used to construct the array, but it doesn't need to be constructed in-place \$\endgroup\$c--– c--2022年10月17日 13:51:27 +00:00Commented Oct 17, 2022 at 13:51
C# (.NET Core) (削除) 120 (削除ここまで) (削除) 117 (削除ここまで) 107 bytes
Here is a C# version based of the Dart and Go examples.
Func<Func<int,bool>,Func<int,bool>,Func<int,bool>>f=(l,r)=>{var s=1<0;return v=>l(v)?s=!s:r(v)?!(s=!s):s;};
Shaved off 3 bytes by replacing
false
with1<0
and a non needed space. Hat tip to jdtShaved off 10 bytes by not doing boolean wizardry
Ungolfed main version:
var flipflop = new Func<Func<int,bool>, Func<int, bool>, Func<int,bool>> ( (condition1,condition2) => {
var flipflop = false;
return new Func<int,bool>(value => {
if (condition1(value))
{
flipflop = !flipflop;
} else if (condition2(value)) {
flipflop = !flipflop;
return true;
}
return flipflop;
});
});
How you use it:
var flop = f(v => v == 2, v => v == 8);
for(var x = 0; x< 11; x++)
{
if (flop(x)) {
Console.WriteLine(x);
}
}
C# (.NET Core), 91 bytes
Using a delegate as proposed by jdt
delegate bool d(int i);Func<d,d,d>f=(l,r)=>{var s=1<0;return v=>l(v)?s=!s:r(v)?!(s=!s):s;};
Go, 131 bytes, int
s only
func m(l,r func(int)bool)func(int)bool{f:=1<0
return func(t int)bool{if!f&&l(t){f=!f;return f}
if f&&r(t){f=!f;return!f}
return f}}
Go, 132 bytes, generic
func m[T any](l,r func(T)bool)func(T)bool{f:=1<0
return func(t T)bool{if!f&&l(t){f=!f;return f}
if f&&r(t){f=!f;return!f}
return f}}
This solution is fully generic for any type T
.
Ungolfed
func makeFlipFlop[T any](l,r func(T)bool) func(T)bool {
flipped := false
return func(t T)bool {
if !flipped && l(t) {flipped = true; return true}
if flipped && r(t) {flipped = false; return true}
return flipped
}
}
Dart, 42 bytes
f(f,s,[b=1<0])=>(i)=>b?b|(b=!s(i)):b=f(i);
You use it as:
void main() {
var flipflop = f((i)=>i % 3 == 0, (i) => i % 7 == 0);
for (var i = 1; i < 15; i++) {
if (flipflop(i)) print(i);
}
}
Which prints 3,4,5,6,7,9,10,11,12,13,14.
It even allows you to pass in an extra Boolean to make it the active state.
In a less horribly mangled and more typed version, it would be:
bool Function(T) flipflop<T>(bool Function(T) from, bool Function(T) until) {
bool b = false;
return (T value) {
if (b) {
b = !until(value);
return true;
}
b = from(value);
return b;
}
}
Nim, 100 bytes
import sugar
var s,t=off
proc f(x,y:int->bool):proc=(z:int)=>(s=s or z.x;t=s;s=s and not z.y;s or t)
Works with int
-typed inputs, uses a couple of globals to store the current and previous states.
Unfortunately, Nim doesn't let us omit type annotations, unless we are supplying the lambda directly as an argument to a higher-order function (as in test cases in the footer), so this ends up rather verbose. Importing syntax sugar macros ->
and =>
allows getting rid of some repetitive annotations and thus, pays off by a few bytes.
As a bonus, Nim also allows defining operators, so that we can mimick Ruby's behavior precisely:
Pyth, 11 bytes
L+Z=?Z!PbOb
Pyth doesn't have any way to take functions as arguments, nor any way to return a function. So here we do the next best thing, which is to define a function which will implement the required behavior on the two functions O
and P
. That is to say that when we call y
it will flip-flop on whatever O
and P
are defined as. The try it online link above links to a full working example which is the same as the first example in the question, I'll explain below.
DOdRqd2; define O(d): (d==2)
DPdRqd8; define P(d): (d==8)
L+Z=?Z!PbOb implement y as the flip-floperator
VQyN loop N over range(0,input()) and print the output of y(N)
And the actual flip-floperator
L define y(b)
+Z sum of previous output and
?Z ternary on previous output
!Pb not P(b) if Z currently True
Ob O(b) if Z currently False
= assign result of ternary to Z
C++ (clang), (削除) 123 (削除ここまで) 101 bytes
struct F{int r=0;template<class A,class B>int operator()(A a,B b,int t){return r|(r^=r?b(t):a(t));}};
- actually we can go to 92 Bytes if we just implemented a class function h for example but it's no more exactly a closure.
Assumes predicates take int type, generalize also predicates will cost a few Bytes.
Due to implicit type conconversion can work with strings.
Struct F is a closure with operator () defined to behave flipFlop.
Saved 22 Bytes by templatizing operator () instead of the entire class.
Approach stolen from @Arnauld answer where r keeps the state of flipFlop.
-
-
\$\begingroup\$ @jdt yes the heavy use of signatures is a bit boring, I also tried a typedef without savings. Anyway now there's c-- great answer so if I touch this will be for deleting \$\endgroup\$AZTECCO– AZTECCO2022年10月15日 21:09:56 +00:00Commented Oct 15, 2022 at 21:09
PHP 67 bytes
function f($i,$a,$b){static$k=0;$r=$k;return$r|$k^=($k?$b:$a)($i);}
$k must be copied to a temp variable because the ^=
is executed before the |
,
although both operators are LTR.
Just define your two functions and give them to f
as parameters within the loop.
The functions may be anonymous or named, or even predefined.
e.g.
# example 1
$a=function($i){return$i==2;} $b=function($i){return$i==8;}
for($i=0;$i<=10;$i++) f($i,$a,$b) && print "$i ";
or
# example 2
function a($i){return$i%5==0;} function b($i){return$i%5==2;}
for($i=0;$i<=10;$i++) f($i,'a','b') && print "$i ";
# important: function names must be quoted to avoid "undefined constant" error (in PHP 8)
or
# other example
for($i=0;$i<=10;$i++) f($i,'intval',function($i){return$i<5;) && print "$i ";
# prints 1 2 3 4 5 6 7 8 9 10
# ('$i<5' is irrelevant because testing 'intval' immediately resumes the printing)
Microsoft Excel, 156
Phew... this is quite difficult in a language that doesn't let you alter variables or have objects.
It doesn't quite meet the requirements, but I think it fits the spirit of the challenge. In this implementation, the flip flop function has to encode its output in a LAMBDA that returns the actual value. Unfortunately, that was the best I could figure out. I felt this was a better compromise than just letting myself add a parameter to the flip-flop function. Fortunately, it's easy to decode.
Golfed:
LAMBDA(a,b,LET(f,LAMBDA(g,o,d,e,LAMBDA([v],IF(ISOMITTED(v),o,IF(g(v),d(d),e(e))))),p,LAMBDA(s,f(a,0=1,LAMBDA(u,f(b,1=1,LAMBDA(_,f(a,1=1,u,s)),u)),s)),p(p)))
Ungolfed:
LAMBDA(a,b,
LET(
f,LAMBDA(g,o,d,e,LAMBDA([v],IF(ISOMITTED(v),o,IF(g(v),d(d),e(e))))),
p,LAMBDA(s,
f(a,0=1,LAMBDA(u,
f(b,1=1,LAMBDA(_,
f(a,1=1,u,s)
),u)
),s)
),
p(p)
)
)
Usage example:
=LET(
makeFF,LAMBDA(a,b,LET(f,LAMBDA(g,o,d,e,LAMBDA([v],IF(ISOMITTED(v),o,IF(g(v),d(d),e(e))))),p,LAMBDA(s,f(a,0=1,LAMBDA(u,f(b,1=1,LAMBDA(_,f(a,1=1,u,s)),u)),s)),p(p))),
MAP(
SCAN(
makeFF(LAMBDA(x,x=3),LAMBDA(x,x=7)),
SEQUENCE(10),
LAMBDA(x,y,x(y))
),
LAMBDA(x,x())
)
)
How does it work?
- We take advantage of the fact that
SCAN
can hold intermediate values by storing aLAMBDA
. - This lambda returns the following:
- If called with no arguments, the value of the flip-flop
- If called with a value, returns another lambda that represents the state of the flip-flop. This one can also be called with no arguments or a value argument (and so on, recursively).
- So per iteration of
SCAN
, we call it with the input value to get an array of lambdas, then we callMAP
to "decode" them by invoking these with no arguments.
How does this track the state of the flip-flop?
- The flip-flop generator returns a state machine. Each state is also a
LAMBDA
.- Input
v
- State 1: Value is
FALSE
, goes to 2 if a(v), else goes to 1 - State 2: Value is
TRUE
, goes to 3 if b(v), else goes to 2 - State 3: Value is
TRUE
, goes to 2 if a(v), else goes to 1 - If
v
is omitted, output the state.
- Input
- The function
f
is a helper for defining the state property (return value and transition functions)
Why can't you...
- Just use
SCAN
to track the state directly? Because this would require passing the state to the flip-flop. The flip-flop only takes the one value argument according to the challenge rules. Otherwise, you'd have to call the flip-flop generator on every iteration ofSCAN
, which is also not valid. - Use recursion instead of
MAP
+SCAN
? I probably could have, but I'd still have to unpack the value. This was just easier to think about. You'd have to do that for Google Sheets, though, because you're not currently allowed to call LAMBDA's stored in arrays.
..
operator wouldn't even fit the spec, even if converted to a conventional prefix function, since it appears to take two expressions evaluated as truthy/falsy as operands, rather than two functions and a single value... \$\endgroup\$true
and gets "flipped" by the second operand, it returnstrue
once before it starts returningfalse
. It sounds weird but makes sense in the context of matching an inclusive range of lines in a text file, which is its conventional use. \$\endgroup\$(i==2)..(i==2)
. In the original Ruby variant, this firestrue
once, as it corresponds to a 1-element range2..2
. But many current answers that rely onxor
operation would fail this test. \$\endgroup\$