// RUN: not %target-swift-frontend %s -parse

/// Abstraction of numeric types that approximate real numbers
protocol ApproximateRealType {
  init() // zero
  func * (Self,Self) -> Self
  func + (Self,Self) -> Self
  func / (Self,Self) -> Self
  func - (Self,Self) -> Self
  prefix func + (Self) -> Self
  prefix func - (Self) -> Self
}

extension Double : ApproximateRealType {}
extension Float : ApproximateRealType {}

// Abstraction of a mathematical vector
protocol VectorType {
  init()
  typealias Element : ApproximateRealType
  func dotProduct(Self) -> Element


  // Extras
  var count: Int {get}
  subscript(Int) -> Element {get set}
  typealias Tail
}

struct EmptyVector<T: ApproximateRealType> : VectorType {
  init() {}
  typealias Element = T
  func dotProduct(other: EmptyVector) -> Element {
    return Element() // zero
  }
  var count: Int { return 0 }
  
  subscript(i: Int) -> Element {
    get { fatalError("subscript out-of-range") }
    set { fatalError("subscript out-of-range") }
  }
}

struct Vector<Tail: VectorType> : VectorType {
  typealias Element = Tail.Element
  
  init(head: Element, tail: Tail) {
    self.head = head
    self.tail = tail
  }

  init() {
    self.head = Element()
    self.tail = Tail()
  }

  /*
  init(scalar: Element) {
    self.head = Element()
    self.tail = Tail()
  }
  */
  
  func dotProduct(other: Vector) -> Element {
    return head * other.head + tail.dotProduct(other.tail)
  }

  var count: Int { return tail.count + 1 }
  var head: Element
  var tail: Tail

  subscript(i: Int) -> Element {
    get { return i == 0 ? head : tail[i - 1] }
    set { if i == 0 { head = newValue } else { tail[i - 1] = newValue } }
  }
}

extension VectorType where Tail == EmptyVector<Element> {
  init(_ scalar: Element) {
    self.init()
    self[0] = scalar
  }
}

//===--- A nice operator for composing vectors ----------------------------===//
//===--- there's probably a more appropriate symbol -----------------------===//
infix operator ⋮ {
  associativity right
  precedence 1
}

func ⋮ <T: ApproximateRealType> (lhs: T, rhs: T) -> Vector<Vector<EmptyVector<T> > > {
  return Vector(head: lhs, tail: Vector(head: rhs, tail: EmptyVector()))
}
func ⋮ <T: ApproximateRealType, U where U.Element == T> (lhs: T, rhs: Vector<U>) -> Vector<Vector<U> > {
  return Vector(head: lhs, tail: rhs)
}

extension Vector : CustomDebugStringConvertible {
  var debugDescription: String {
    if count == 1 {
      return "Vector(\(String(reflecting: head)))"
    }
    return "\(String(reflecting: head)) ⋮ " + (count == 2 ? String(reflecting: self[1]) : String(reflecting: tail))
  }
}

//===--- Test -------------------------------------------------------------===//
print(Vector(head: 3.0, tail: EmptyVector()))
print(3.0 ⋮ 4.0 ⋮ 5.0)
print( (3.0 ⋮ 4.0 ⋮ 5.0).dotProduct(6.0 ⋮ 7.0 ⋮ 8.0) ) // 86.0

// print( (3.0 ⋮ 4.0 ⋮ 5.0).dotProduct(6.0 ⋮ 7.0) ) // Won't compile

