Must relational algebra use tuples?

108 Views Asked by At

Please excuse me if I make glaring mistakes below – I'm a software engineer rather than a mathematician or logician, but I'm trying!

My understanding of relational algebra is that relation headings and their body sets are defined in terms of tuples.

My question is basically – could something similarly powerful to relational algebra "fit together" if all that "relations" had is a set of values from an arbitrary domain. Particularly, I'm thinking of sets of "Value Types" in a programming language, which would be immutable and equatable.

I've not seen a reason yet why this wouldn't work, and in terms of building software, it feels like it might be convenient.

So, given that my language has a Set implementation, I can do the following:

extension Set {
  func select(_ predicate: (Element) -> Bool) -> Set<Element> {
    return Set(filter(predicate))
  }

  func project<CoDomain>(_ transform: (Element) -> CoDomain) -> Set<CoDomain> {
    return Set<CoDomain>(map(transform))
  }
}

func *<A, B>(_ a: Set<A>, _ b: Set<B>) -> Set<CrossProduct<A,B>> {
  var result = Set<CrossProduct<A,B>>()
  a.forEach { (aElement) in
    b.forEach({ (bElement) in
      result.insert(CrossProduct(aElement, bElement))
    })
  }
  return result
}

struct CrossProduct<A: Hashable & Equatable, B: Hashable & Equatable> {
  let a: A
  let b: B

  init(_ a: A, _ b: B) {
    self.a = a
    self.b = b
  }
}

Set already has operations for intersection, union, difference, etc. The CrossProduct struct here is to address an unfortunate omission in Swift that its raw tuples can't be put in to a Set.

With these, if I've got my data in sets of values, I can start building up queries on it:

struct Customer {
  let name: String
  let id: Int
}

let customers = Set([Customer(name:"Ben", id:1),
                     Customer(name:"Sally", id:2),
                     Customer(name:"Ben", id:3),
                     Customer(name:"Misa", id:4)])

let names = customers.project($0.name)

Which would result in names being {"Ben", "Sally", "Misa"}.

(The project method here could also be used to perform domain computation on the set members. Given complex numbers, it could rotate, them, for example.)

A struct Order could also be defined, and we could join a set of orders to customers using * followed by select to see the orders particular customers have made.

So … if this direction of thought is doomed to failure and lack of expression for some reason, I'd love to know before I go much further with it!

My suspicion is that this probably ought to work. Because one could define a relation that had a single heading value of any chosen domain. Which seems equivalent to what I'm proposing. But I could be overlooking many problems with this!

It occurs to me that perhaps the advantage of a tuple based relational algebra is not expressive power, but the opposite: perhaps it imposes useful restrictions that ensure some efficiency bound of queries?

Thank you.