<commit_before>package com.github.prologdb.runtime.stdlib.essential.dynamic

import com.github.prologdb.async.buildLazySequence
import com.github.prologdb.async.launchWorkableFuture
import com.github.prologdb.async.mapRemaining
import com.github.prologdb.runtime.PrologRuntimeException
import com.github.prologdb.runtime.stdlib.nativeRule
import com.github.prologdb.runtime.term.CompoundTerm
import com.github.prologdb.runtime.term.PrologInteger
import com.github.prologdb.runtime.term.PrologList
import com.github.prologdb.runtime.term.Term
import com.github.prologdb.runtime.term.Variable
import com.github.prologdb.runtime.unification.Unification
import com.github.prologdb.runtime.unification.VariableBucket

/**
 * findnsols(+N, @Template, :Goal, -List)
 * Like findall/3 but finds at most N solutions
 */
val BuiltinFindNSols4 = nativeRule("findnsols", 4) { args, context ->
    val nSolutions = args[0]
    val templateInput = args[1]
    val goalInput = args[2]
    val solutionInput = args[3]

    if (nSolutions !is PrologInteger) throw PrologRuntimeException("Type error: argument 1 to findnsols/4 must be an integer, got ${nSolutions.prologTypeName}")

    if (goalInput !is CompoundTerm) throw PrologRuntimeException("Type error: argument 3 to findnsols/4 must be a query.")

    if (solutionInput !is Variable) throw PrologRuntimeException("Type error: argument 4 to findnsols/4 must be unbound.")

    val resultList = await(launchWorkableFuture(principal) {
        val resultSequence = buildLazySequence<Unification>(principal) {
            context.fulfillAttach(this, compoundToQuery(goalInput), VariableBucket())
        }
            .limitRemaining(nSolutions.value)
            .mapRemaining { solution ->
                templateInput.substituteVariables(solution.variableValues.asSubstitutionMapper())
            }

        foldRemaining(resultSequence, mutableListOf<Term>()) { l, t -> l.add(t); l }
    })

    val resultListUnified = solutionInput.unify(PrologList(resultList), context.randomVariableScope)
    resultListUnified.variableValues.retainAll(templateInput.variables + solutionInput.variables)
    return@nativeRule resultListUnified
}
<commit_msg>stdlib: findnsols/4 accepts a list as the fourth parameter<commit_after>package com.github.prologdb.runtime.stdlib.essential.dynamic

import com.github.prologdb.async.buildLazySequence
import com.github.prologdb.async.launchWorkableFuture
import com.github.prologdb.async.mapRemaining
import com.github.prologdb.runtime.PrologRuntimeException
import com.github.prologdb.runtime.stdlib.nativeRule
import com.github.prologdb.runtime.term.CompoundTerm
import com.github.prologdb.runtime.term.PrologInteger
import com.github.prologdb.runtime.term.PrologList
import com.github.prologdb.runtime.term.Term
import com.github.prologdb.runtime.term.Variable
import com.github.prologdb.runtime.unification.Unification
import com.github.prologdb.runtime.unification.VariableBucket

/**
 * findnsols(+N, @Template, :Goal, -List)
 * Like findall/3 but finds at most N solutions
 */
val BuiltinFindNSols4 = nativeRule("findnsols", 4) { args, context ->
    val nSolutions = args[0]
    val templateInput = args[1]
    val goalInput = args[2]
    val solutionInput = args[3]

    if (nSolutions !is PrologInteger) throw PrologRuntimeException("Type error: argument 1 to findnsols/4 must be an integer, got ${nSolutions.prologTypeName}")

    if (goalInput !is CompoundTerm) throw PrologRuntimeException("Type error: argument 3 to findnsols/4 must be a query.")

    if (solutionInput !is Variable && solutionInput !is PrologList) throw PrologRuntimeException("Type error: argument 4 to findnsols/4 must be unbound or a list, got ${solutionInput.prologTypeName}")

    val resultList = await(launchWorkableFuture(principal) {
        val resultSequence = buildLazySequence<Unification>(principal) {
            context.fulfillAttach(this, compoundToQuery(goalInput), VariableBucket())
        }
            .limitRemaining(nSolutions.value)
            .mapRemaining { solution ->
                templateInput.substituteVariables(solution.variableValues.asSubstitutionMapper())
            }

        foldRemaining(resultSequence, mutableListOf<Term>()) { l, t -> l.add(t); l }
    })

    val resultListUnified = solutionInput.unify(PrologList(resultList), context.randomVariableScope)
    resultListUnified?.variableValues?.retainAll(templateInput.variables + solutionInput.variables)
    return@nativeRule resultListUnified
}

{'fraction_non_alphanumeric': 0.09575649855587647, 'fraction_numerical': 0.005998666962897134, 'mean_word_length': 4.620474406991261, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1378466', 'n_tokens_mistral': 1349, 'n_tokens_neox': 1297, 'n_words': 274}