ごもっとも。

0と1を次々返す方法 - a2c.get.diary
TrueだったらFalseで、FalseだったらTrueにしたい。
なんかそんなことそこかしこで必要で、その為の便利なものが
あるのかなぁと思ったんだけど無いぽい

Closure

本来は一番おすすめなのだが…

JavaScript

()が煩わしいが、perlやrubyよりは自然。

#!/usr/bin/js
var flipflop = function(p){
  p = !p;
  return function(){
    return p = !p;
  };
};

var fl = flipflop();
console.log(fl());
console.log(fl());
console.log(fl());
console.log(fl());

Perl

->()がわずらわしい。

#!/usr/bin/perl
use 5.010;
use strict;
use warnings;

sub flipflop{
  my $p = !shift;
  sub { $p = !$p }
}

my $fl = flipflop();
say $fl->();
say $fl->();
say $fl->();
say $fl->();

Ruby

callは煩わしいし[]はきしょい。

#!/usr/bin/ruby
def flipflop(p=false)
  p = !p
  Proc.new{ p = !p }
end

fl = flipflop()
puts fl.call
puts fl.call
puts fl[]    # .call の代わりにOK
puts fl[]

Python

Pythonの鬼門はClosureかも知れない。なんとこれが動かない。

def flipflop(p=False):
  p = not p
  def ret():
    p = not p
    return p
  return ret

fl = flipflop()
print fl()
print fl()
print fl()
print fl()

Python 3だと何とか書けるが…

def flipflop(p=False):
  p = not p
  def ret():
    nonlocal p
    p = not p
    return p
  return ret

fl = flipflop()
print(fl())
print(fl())
print(fl())
print(fl())

nonlocalがきしょい。

Class + Operator Overloading

Perl

実装はとにかく、利用はこれが一番自然かも知れない。

#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
{
    package FlipFlop;
    use overload
      'bool' => \&fetch,
      '0+'   => \&numify,
      '""'   => \&numify
      ;
    sub new {
        my $class = shift;
        my $self  = !shift;
        bless \$self, $class;
    }
    sub fetch {
        my $self = shift;
        $$self = !$$self;
    }
    sub numify {
      shift->fetch + 0;
    }
}

my $fl = new FlipFlop;
say $fl;
say $fl;
say $fl;
say $fl;

python

bool()でキャストしなければならないのが煩わしい。

#!/usr/bin/python
class FlipFlop:
  def __init__(self, v=False):
    self.x = not bool(v)
  def __nonzero__(self):
    self.x = not self.x
    return self.x

fl = FlipFlop()
print bool(fl)
print bool(fl)
print bool(fl)
print bool(fl)
print fl

ruby

puts oo.to_sが暗黙で呼ばれるのと異なり、#to_boolに相当するメソッドが論理演算の時に暗黙で呼ばれるということはない。後述のYieldの例に似てしまう。

#!/usr/bin/ruby
class FlipFlop
  def initialize(init=false)
    @p = !init
  end
  def to_b
    @p = !@p
  end
end

fl = FlipFlop.new()
puts fl.to_b
puts fl.to_b
puts fl.to_b
puts fl.to_b
puts fl && true # false になってはくれない

Yield

python

実装は自然だが、next()がわずらわしい。

#!/usr/bin/python
def flipflop(p=False):
  p = not not p
  while True:
    yield p
    p = not p

fl = flipflop();
print fl.next();
print fl.next();
print fl.next();
print fl.next();

JavaScript 1.7(参考)

現状Firefox/SpiderMonkeyしかサポートしていない。

var flipflop = function(p){
  p = !!p;
  while(true){
    yield p;
    p = !p;
  };
};

var fl = flipflop();
console.log(fl.next());
console.log(fl.next());
console.log(fl.next());
console.log(fl.next());

Macro

C

意外といける?

#define flip(p) !((p) = !(p))

void main(){
  int p = 0;
  printf("%d\n", flip(p));
  printf("%d\n", flip(p));
  printf("%d\n", flip(p));
  printf("%d\n", flip(p));
}

回数を気にしなければこれでも。

#define flip(p) ((p)++ & 1)

void main(){
  int p = 0;
  printf("%d\n", flip(p));
  printf("%d\n", flip(p));
  printf("%d\n", flip(p));
  printf("%d\n", flip(p));
}

簡単なお仕事だけあって、やり方も多すぎる…

Dan the Binary Blogger

追記

Perl

Re: Algorithm - 0と1を次々と返す簡単なお仕事 - TokuLog 改メ tokuhirom’s blog
Perl5.10 なら state がつかえるから、以下のように書けるのではないか。
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
use Test::More;

sub flipflop {
    state $p = !shift;
    $p = !$p
}

ok !flipflop();
ok flipflop();
ok !flipflop();
ok flipflop();

done_testing;

stateを避けたのは、$pを共有したくない、要するにsingletonにしたくなかったから。要は

my $true1st  = flipflop(1);
my $false1st = flipflop(0);

としたかった、と。でもsingletonでいいならstateがベストプラクティスだと私も思う。

Python

@dankogai python版は__nonzero__ではなく__call__を定義すればboolにキャストする必要ないのでは。 QT: 404 Blog Not Found:Algorithm - 0と1を次々と返す簡単なお仕事 http://htn.to/bGWDnqless than a minute ago via web

()が必要とはいえ、これが一番よさげ。

#!/usr/bin/python
class FlipFlop:
  def __init__(self, v=False):
    self.x = not bool(v)
  def __call__(self):
    self.x = not self.x
    return self.x

fl = FlipFlop()
print fl()
print fl()
print fl()
print fl()
print fl

JavaScript

Re: Algorithm - 0と1を次々と返す簡単なお仕事 - 葉っぱ日記
JavaScript で呼び出しの () が煩わしいなら、以下のように書けるのではないか。

というわけで少し改変。JSはこれで決定かな?

#!/usr/bin/js
var flipflop = function(p){
  return {
    p : 0,
    valueOf : function(){ return this.p = !this.p; },
    toString : valueOf
  };
};
var fl = flipflop();
console.log(+fl);
console.log(+fl);
console.log(+fl);
console.log(+fl);
console.log(fl);