проверка вероятности распределения с переменными аргументами суммы до 1 - PullRequest
7 голосов
/ 10 октября 2011

Мне было интересно, как бы вы написали метод в Scala, который принимает функцию f и список аргументов args, где каждый аргумент является диапазоном. Предположим, у меня есть три аргумента (Range(0,2), Range(0,10) и Range(1, 5)). Затем я хочу перебрать f со всеми возможностями этих трех аргументов.

var sum = 0.0
for (a <- arg(0)) {
  for (b <- arg(1)) {
    for (c <- arg(2)) {
      sum += f(a, b, c)
    }
  }
}

Однако я хочу, чтобы этот метод работал для функций с переменным числом аргументов. Это возможно?

Редактировать: есть ли способ сделать это, когда функция не берет список, а принимает стандартный список параметров или карри?

Ответы [ 4 ]

6 голосов
/ 10 октября 2011

Это действительно хороший вопрос!

Вы хотите последовательно запустить flatMap в списке элементов произвольного размера. Если вы не знаете, какой длины ваш список, вы можете обработать его с помощью рекурсии или, что то же самое, со сгибом.

scala> def sequence[A](lss: List[List[A]]) = lss.foldRight(List(List[A]())) {
     |    (m, n) => for (x <- m; xs <- n) yield x :: xs
     | }
scala> sequence(List(List(1, 2), List(4, 5), List(7)))
res2: List[List[Int]] = List(List(1, 4, 7), List(1, 5, 7), List(2, 4, 7), List(2
, 5, 7))

(Если вы не можете разобраться в коде, не волнуйтесь, узнайте, как использовать Hoogle и украдите его у Haskell )

Это можно сделать с помощью Scalaz (обычно он начинается с F[G[X]] и возвращает G[F[X]], учитывая, что конструкторы типов G и F имеют возможности Traverse и Applicative соответственно.

scala> import scalaz._
import scalaz._

scala> import Scalaz._
import Scalaz._

scala> List(List(1, 2), List(4, 5), List(7)).sequence
res3: List[List[Int]] = List(List(1, 4, 7), List(1, 5, 7), List(2, 4, 7), List(2
, 5, 7))

scala> Seq(some(1), some(2)).sequence
res4: Option[Seq[Int]] = Some(List(1, 2))

scala> Seq(some(1), none[Int]).sequence
res5: Option[Seq[Int]] = None
1 голос
/ 10 октября 2011

Это более или менее выполнит эту работу (без применения f, которое вы можете сделать отдельно)

  def crossProduct[A](xxs: Seq[A]*) : Seq[Seq[A]] 
    = xxs.foldLeft(Vector(Vector[A]())){(res, xs) => 
      for(r <- res; x <- xs) yield r :+ x
    }

Затем вы можете просто сопоставить свою функцию с этим.Я не уверен, что это очень эффективная реализация.

0 голосов
/ 10 октября 2011

Посмотрите на этот ответ . Я использую этот код именно для этой цели. Это немного оптимизировано. Я думаю, что я мог бы создать более быструю версию, если вам нужна.

0 голосов
/ 10 октября 2011

Это ответ с рекурсивной точки зрения. К сожалению, не такой короткий, как другие.

def foo(f: List[Int] => Int, args: Range*) = {
    var sum = 0.0
    def rec(ranges: List[Range], ints: List[Int]): Unit = {
      if (ranges.length > 0)
        for (i <- ranges.head)
          rec(ranges.tail, i :: ints)
      else
        sum += f(ints)
    }
    rec(args.toList, List[Int]())
    sum
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...