Is there a functional programming concept equivalent to the flip-flop operator in Perl or Ruby?
Asked Answered
T

3

7

Ruby (and Perl) has a concept of the flip flop:

file = File.open("ordinal")
while file.gets
  print if ($_ =~ /third/) .. ($_ =~ /fifth/)
end

which given a list of ordinals, such as

first
second
third
fourth
fifth
sixth

would start printing when it reached "third" and stop when it reached "fifth":

third
fourth
fifth

Is there a functional programming concept analogous to this, or would this normally be described in terms of takewhiles? I'm not asking about a particular language, just what term you'd use to describe it.

Towle answered 23/6, 2011 at 23:58 Comment(2)
Which languages are you considering for FP? There are many different approaches, and some may meet your needs. Also, are you, in this example, just typing the third - fifth lines? You may want to explain in more detail what you are hoping happens.Mckeever
@James Black: How is the new version of the question?Towle
J
8

In a functional language such as haskell, you would pass in the flip and flop conditions as predicates, and filter an input list based on it. For example, the following is a definition of flipflop in haskell (don't worry about the implementation if you don't know haskell - the key part is how it is used):

flipflop flip flop = 
  uncurry (++) . second (take 1) . break flop . dropWhile (not . flip)

This is how it can be used:

> flipflop (== 3) (== 5) [1..10]
[3,4,5]

It is an example of making an effectively new language construct just by using higher ordered function.

I don't know if there is a special name for that construct in functional languages.

Janessa answered 24/6, 2011 at 4:46 Comment(0)
D
4

Depends on functional language. How about this?

ff_gen =
  lambda{ |first, *conditions| 
    flipflop = false
    condition = first
    lambda{ |v| 
      if condition && condition[v]
        condition = conditions.shift
        flipflop = !flipflop
        true
      else
        flipflop
      end
    }
  }

ff = ff_gen[lambda{|v| v == 3}, lambda{|v| v == 5}, lambda{|v| v == 7}, lambda{|v| v == 11}]

puts (0..20).select{ |i| ff[i] }.inspect # => [3, 4, 5, 7, 8, 9, 10, 11]

Added: Of course, Ruby is not a pure functional language, so I decided to rewrite it in Erlang:

#!/usr/bin/env escript

flipflop(E, {[H|T] = Conditions, FlipFlop}) ->
  case H(E) of
    true ->
      {true, {T, not FlipFlop}};
    false ->
      {FlipFlop, {Conditions, FlipFlop}}
  end;

flipflop(_, {[], FlipFlop}) ->
  {FlipFlop, {[], FlipFlop}}.

flipflop_init(Conditions) ->
  {[], {Conditions, false}}.

main([]) ->
  {L, _} = 
    lists:foldl(
      fun(E, {L2, FFState}) -> 
        case flipflop(E, FFState) of
          {true, FFState2} ->
            {[E|L2], FFState2};
          {false, FFState2} ->
            {L2, FFState2}
        end
      end,
      flipflop_init([
        fun(E) -> E == 3 end, 
        fun(E) -> E == 5 end, 
        fun(E) -> E == 7 end, 
        fun(E) -> E == 11 end
      ]), 
      lists:seq(0,20)
    ),
  io:format("~p~n", [lists:reverse(L)]),
  ok.

Note: In fact, classic flip-flop should work like dropwhile(!first) -> takewhile(!second), so Ruby's flip-flop is ad hoc one (compare with flip-flop in electronics).

Detrude answered 24/6, 2011 at 0:46 Comment(1)
Do you know if there's a term describing the concept?Towle
A
0

Same as @nanothief's solution, but in Scala:

def flipFlop[A](flip: A => Boolean, flop: A => Boolean, seq: Seq[A]): Seq[A] = {
  val (p, q) = seq.dropWhile(!flip(_)).span(!flop(_))
  p ++ q.take(1)
}

Sample runs:

> flipFlop[Int](_ == 3, _ == 5, Nil)
List()

> flipFlop[Int](_ == 3, _ == 5, 1 to 19)
Vector(3, 4, 5)
Atkins answered 24/6, 2011 at 7:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.