                 fatalError("DISTINCT aggregation is unimplemented")
             }
             let expr = try parseNonAggregatingExpression()
-            fatalError("SAMPLE aggregate is unimplemented")
             try expect(token: .rparen)
+            fatalError("implement SAMPLE aggregate \(expr)")
         case "GROUP_CONCAT":
             try expect(token: .lparen)
             if try attempt(token: .keyword("DISTINCT")) {

                algebra = .extend(algebra, expr, name)
            } else {
                guard let c = freshCounter.next() else { fatalError("No fresh variable available") }
                let name = ".\(c)"
                algebra = .extend(algebra, expr, name)
                node = .variable(name, binding: true)
            }

    }
    
    private mutating func triplesByParsingCollectionAsNode() throws -> (Node, [Algebra]) { fatalError("implement") }
    
    private mutating func triplesByParsingCollectionPathAsNode() throws -> (Node, [Algebra]) {
        try expect(token: .lparen)
        let (node, graphNodePath) = try parseGraphNodePathAsNode()
        var triples = graphNodePath
        var nodes = [node]
        while try !peek(token: .rparen) {
            let (node, graphNodePath) = try parseGraphNodePathAsNode()
            triples.append(contentsOf: graphNodePath)
            nodes.append(node)
        }
        try expect(token: .rparen)
        
        let bnode = self.bnode()
        var list = bnode
        
        let rdffirst = Term(value: "http://www.w3.org/1999/02/22-rdf-syntax-ns#first", type: .iri)
        let rdfrest = Term(value: "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest", type: .iri)
        let rdfnil = Term(value: "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil", type: .iri)
        
        var patterns = [TriplePattern]()
        if nodes.count > 0 {
            for (i, o) in nodes.enumerated() {
                let triple = TriplePattern(subject: .bound(list), predicate: .bound(rdffirst), object: o)
                patterns.append(triple)
                if i == (nodes.count-1) {
                    let triple = TriplePattern(subject: .bound(list), predicate: .bound(rdfrest), object: .bound(rdfnil))
                    patterns.append(triple)
                } else {
                    let newlist = self.bnode()
                    let triple = TriplePattern(subject: .bound(list), predicate: .bound(rdfrest), object: .bound(newlist))
                    patterns.append(triple)
                    list = newlist
                }
            }
            triples.append(.bgp(patterns))
        } else {
            let triple = TriplePattern(subject: .bound(list), predicate: .bound(rdffirst), object: .bound(rdfnil))
            triples.append(.bgp([triple]))
        }
        return (.bound(bnode), triples)
    }

    private mutating func parseGraphNodeAsNode() throws -> (Node, [Algebra]) { fatalError("implement") }

    private mutating func parseGraphNodePathAsNode() throws -> (Node, [Algebra]) {
