我有一个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中执行此操作的任何提示也将受到赞赏。
答案 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中的and
和or
没有直接对应的函数,这些函数在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
)。但是,由于组合中的元素数量必须小于或等于集合中元素的数量,因此它在此处不起作用。