Scala функция набора

В курсе Стэнфорда Scala я столкнулся с следующим назначением:

Упражнение 1 - Наборы как функции:

В этом упражнении мы будем представлять множества как функции от Ints до Booleans:

type Set = Int => Boolean

a) Напишите функцию "set", которая принимает параметр Int и возвращает набор, содержащий этот Int.

b) Напишите функцию "содержит", которая принимает параметры Set и Int как параметры и возвращает true, если Int в Set и false в противном случае.

c) Напишите функции "union", "intersect" и "минус", которые берут два набора в качестве параметров и возвращают Set.

d) Можете ли вы написать функцию "подмножество", которая принимает два набора в качестве параметров и возвращает true, если первый является подмножеством второго и false в противном случае?

Решения для a, b и c довольно тривиальны:

def set(i: Int): Set = n => n == i

def contains(s: Set, i: Int) = s(i)

def union(a: Set, b: Set): Set = i => a(i) || b(i)

def intersect(a: Set, b: Set): Set = i => a(i) && b(i)

def minus(a: Set, b: Set): Set = i => a(i) && !b(i)

Но есть ли элегантное решение для d? Конечно, строго говоря, ответ d - "да", так как я могу написать что-то вроде:

def subset(a: Set, b: Set) = Int.MinValue to Int.MaxValue filter(a) forall(b)

но это, вероятно, не правильный путь.

Ответы

Ответ 1

Я не думаю, что это возможно без повторения всех целых чисел. Для псевдоподтверждения посмотрите на нужный тип:

def subset: (a: Set, b: Set): Boolean

Как-то нам нужно создать Boolean, когда все, с чем мы должны работать, - это наборы (a, b) типа Int => Boolean и целочисленное равенство (Int, Int) => Boolean. Из этих примитивов единственный способ получить значение Boolean - начать с значений Int. Поскольку у нас нет каких-либо конкретных Int в наших руках, единственный вариант - перебрать все из них.

Если бы у нас был волшебный оракул, isEmpty: Set => Boolean, история была бы иной.

Последняя опция - это кодировать "false" как пустой набор и "true" как что-либо еще, тем самым изменяя желаемый тип:

def subset: (a: Set, b: Set): Set

С помощью этой кодировки логический "или" соответствует операции set union, но я не знаю, что логическое "и" или "не" может быть легко определено.

Ответ 2

Мы имеем

Set A = 
    Returns the intersection of the two given sets,
    the set of all elements that are both in `s` and `t`.

Set B = 
    Returns the subset of `s` for which `p` holds.

Не установлено А ​​равно эквиваленту Set B

def filter(s: Set, p: Int => Boolean): Set = intersect(s, p)

Ответ 3

Я согласен с Kipton Barros, вам нужно будет проверить все значения для Ints, так как вы хотите доказать, что forall x, a(x) implies b(x).

Что касается его оптимизации, я бы, вероятно, написал:

  def subset(a: Set, b: Set) = Int.MinValue to Int.MaxValue exists(i => !a(i) || b(i))

так как !a(i) || b(i) эквивалентно a(i) implies b(i)

Ответ 4

В дальнейшем в упражнениях Coursera вводятся ограниченные множества, а затем forall() и exists() как универсальные и экзистенциальные кванторы по границам. Подмножество() не было в упражнениях, но похоже на forall. Вот моя версия подмножества():

// subset(s,p) tests if p is a subset of p returning true or false
def subset(s: Set, p: Set): Boolean = {
  def iter(a: Int): Boolean = {
    if (a > bound) { true
    } else if (contains(p, a)) {
        if (contains(s, a)) iter(a + 1) else false
    } else iter(a+1)
  }
  iter(-bound)
}

Ответ 5

Вот еще одна версия, использующая функцию:

def union(s: Set, t: Set): Set = x => contains(s,x) || contains(t,x)

def intersect(s: Set, t: Set): Set = x => contains(s,x) && contains(t,x)

def diff(s: Set, t: Set): Set = x => contains(s,x) && !contains(t,x)

def filter(s: Set, p: Int => Boolean): Set = x =>  contains(s, x) && p(x)

Ответ 6

Если существует два набора A и B, то A пересекает B, является подмножеством A и B. Математически доказано: A ∩ B ⊆ A и A ∩ B ⊆ B. Функция может быть записана следующим образом: def filter (s: Set, p: Int = > Boolean): Set = x = > s (x) && & && р (х) или def intersect (s: Set, t: Set): Set = x = > s (x) && & т (х) def filter (s: Set, p: Int = > Boolean): Set = intersect (s, p)