7

Ruby(和 Perl)有一个触发器的概念:

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

它给出了一个序数列表,例如

first
second
third
fourth
fifth
sixth

将在达到“第三”时开始打印,并在达到“第五”时停止:

third
fourth
fifth

是否有与此类似的函数式编程概念,或者这通常会用takewhiles 来描述吗?我不是在问一种特定的语言,只是你会用什么术语来描述它。

4

3 回答 3

8

在诸如 haskell 之类的函数式语言中,您可以将触发器和触发器条件作为谓词传递,并根据它过滤输入列表。比如下面是flipflopin haskell 的定义(不懂haskell的不用担心实现——关键是怎么用):

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

这是它的使用方法:

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

这是仅通过使用高阶函数来构建有效的新语言结构的示例。

我不知道在函数式语言中是否有该构造的特殊名称。

于 2011-06-24T04:46:16.663 回答
4

取决于功能语言。这个怎么样?

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]

补充:当然,Ruby 不是纯函数式语言,所以我决定用 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.

注意:事实上,经典触发器应该像 dropwhile(!first) -> takewhile(!second) 一样工作,所以 Ruby 的触发器是 ad hoc 的(与电子学中的触发器相比)。

于 2011-06-24T00:46:32.387 回答
0

与@nanothief 的解决方案相同,但在 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)
}

样品运行:

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

> flipFlop[Int](_ == 3, _ == 5, 1 to 19)
Vector(3, 4, 5)
于 2011-06-24T07:04:15.420 回答