构建函数应用程序列表

时间:2014-06-12 15:01:22

标签: scala haskell

我有一个Haskell函数,我想将其转换为Scala。 Haskell函数是:

valid3 :: (Bool -> Bool -> Bool -> Bool) -> Bool
valid bf = and [bf p q r | p <- [True, False], 
                           q <- [True, False],
                           r <- [True, False]]

&#39; valid3&#39;是一个高阶函数,因为它将函数作为参数。它作为参数使用的函数接受三个布尔变量并返回一个布尔值。最后valid3返回一个布尔值。

我试图将其翻译成Scala,但我仍然陷入如何在yield部分进行连接的问题。这是我到目前为止(这不是按原样编译):

def valid3 (bf : (Boolean, Boolean, Boolean) => Boolean) : Boolean = {
  for (i <- List(true, false); 
       j <- List(true,false); 
       k <- List(true,false)) yield bf(i,j,k)
}

我不确定我是否在Scala中正确接近这一点。有关如何在惯用Scala中执行此操作的任何提示也将受到赞赏。

2 个答案:

答案 0 :(得分:5)

您的for理解会返回一个列表,以便您forall使用and

def valid3 (bf : (Boolean, Boolean, Boolean) => Boolean) : Boolean = {
  val results = for (i <- List(true, false); 
       j <- List(true,false); 
       k <- List(true,false)) yield bf(i,j,k)
  results.forall(identity)
}

如果您不想要中间变量,可以使用:

def valid3 (bf : (Boolean, Boolean, Boolean) => Boolean) : Boolean = {
  (for (i <- List(true, false); 
        j <- List(true,false); 
        k <- List(true,false)) yield bf(i,j,k))
  .forall(identity)
}
如果谓词对于列表中的每个元素都为true,则

forall接受谓词并返回true。 Haskell中的相应函数是all,其类型为(a -> Bool) -> [a] -> Bool。如果你想在任何列表元素的谓词为真时返回true,你可以使用exists,例如。

results.exists(identity)

这对应于Haskell函数any。据我所知,Scala中的andor没有直接对应的函数,这些函数在Boolean列表上运行,但您可以轻松定义它们:

def or(s: GenTraversableOnce[Boolean]) = s.exists(identity)
def and(s: GenTraversableOnce[Boolean]) = s.forall(identity)

答案 1 :(得分:0)

我有一个与你最初写的完全不同的解决方案,但我认为它更清晰。它也可以推广到三个以上的参数。我使用位操作来生成布尔值的所有组合。

  def findAllBooleanCombos(nArgs: Int): Seq[Seq[Boolean]] = {
    def convertByteToBooleans(byte: Int, nArgs: Int): Seq[Boolean] =
      Range(0, nArgs).map(bitIndex => ((byte >> bitIndex) & 1) == 1)

    Range(0, 1 << nArgs).map(byte => convertByteToBooleans(byte, nArgs))
  }

  val nArgs = 3
  val isAlwaysTrue = findAllBooleanCombos(nArgs).forall(bools => 
                                               f(bools(0), bools(1), bools(2)))

另一种解决方案,它不使用位操作技巧,而且更通用(更多Stream-ish):

  def combinations[A](stream: Stream[A], n: Int): Stream[List[A]] = n match {
    case n if (n <= 0) => throw new IllegalArgumentException()
    case 1 => stream.map(List(_))
    case n =>
      val streamNMinus1: Stream[List[A]] = combinations(stream, n - 1)
      stream.flatMap(a => streamNMinus1.map(listNMinus1 => a :: listNMinus1))
  }
  combinations(Stream(true, false), 3)

编辑:我最近遇到过Scala有一个内置函数combinations,它在很多类型上定义(例如List)。但是,由于组合中的元素数量必须小于或等于集合中元素的数量,因此它在此处不起作用。