J'ai besoin d'écrire (pas de calculer) tous les états de la liste des nombres qui signifie:
Input:
list_sum([Item], Item). list_sum([Item1,Item2 | Tail], Total) :- list_sum([Item1+Item2|Tail], Total).
Output:
1+2+3 1-2-3 1/2/3 1*2*3 1+2-3 1+2/3 1+2*3 1-2+3 1-2/3 1-2*3 1/2+3 1/2-3 1/2+3 1*2+3 1*2-3 1+2-3
dans le code descendant, affichez simplement 1 + 2 + 3
Comment puis-je les développer dans tous les états?
Numbers: 1,2,3 Operators: +,-,/,*
5 Réponses :
Un moyen est
?- all_operations([1,2,3], Out), maplist(writeln, Out). 1*2*3 1*2+3 1*2-3 1*2/3 1+2*3 1+2+3 1+2-3 1+2/3 1-2*3 1-2+3 1-2-3 1-2/3 1/2*3 1/2+3 1/2-3 1/2/3 Out = ['1*2*3', '1*2+3', '1*2-3', '1*2/3', '1+2*3', '1+2+3', '1+2-3', '1+2/3', '1-2*3'|...].
Résultat
member_(In, X) :- member(X, In). get_calcul([N], _, Temp, Out) :- append(Temp, [N], Out). get_calcul([N|T], [Op|Top], Temp, Out) :- append(Temp, [N, Op], Temp1), get_calcul(T, Top, Temp1, Out). all_operations(In, Out) :- % if you have N numbers length(In, Len), % you need N-1 operators LenOps is Len - 1, length(LOps, LenOps), setof(Op, LOps^Ops^(maplist(member_([+,-,*,/]), LOps),get_calcul(In, LOps, [], Ops), atomic_list_concat(Ops, Op)), Out).
Eh bien, j'ai résolu mon problème, pas le vôtre!
Cela peut être fait:
?- all_operations([1,2,3], Out). Out = ['1*2+3', '1*2-3', '1*2/3', '1+2*3', '1+2-3', '1+2/3', '1-2*3', '1-2+3', '1-2/3'|...].
Par exemple:
get_calcul([X], _, Temp, Calcul):- append(Temp, [X], Calcul). get_calcul([N|T], [Op|Top], Temp, Out) :- append(Temp, [N, Op], Temp1), get_calcul(T, Top, Temp1, Out). all_operations(In, Out) :- setof(Op, X^Ops^(permutation([+,-,*,/], X), get_calcul(In, X, [], Ops), atomic_list_concat(Ops, Op)), Out).
qu'en est-il de ['1 + 2 + 3', '1 * 2 * 3', '1/2/3', '1-2-3'] ??
son ne fonctionne pas plus de 3 éléments? pouvez-vous le développer pour plus d'éléments?
Utilisation de DCG avec phrase / 2 en tant que generator :
?- expr(E). E = 1 ; E = 2 ; E = (1, (+), 1) ; E = (1, (+), 2) ; E = (2, (+), 1) ; E = (2, (+), 2) ; E = (1, (*), 1) ; E = (1, (*), 2) ; E = (2, (*), 1) ; E = (2, (*), 2) ; E = (1, (+), 1, (+), 1) ; ... E = (1, (+), 2, (+), 2, (*), 1) ; E = (1, (+), 2, (+), 2, (*), 2) ; E = (1, (+), (1, (+), 1), (+), 1) ; E = (1, (+), (1, (+), 1), (+), 2) ; E = (1, (+), (1, (+), 2), (+), 1) ; ...
Exemple d'exécution:
<expr> ::= <op> <expr> <expr> expr((E1,Op,E2)) --> operator(Op),expr(E1),expr(E2).
Puisque votre question fonctionne avec list, un moyen de voir DCG comme traitement de liste consiste à utiliser listing / 1 pour le convertir en Prologue standard.
<expr> ::= <expr> <op> <expr> expr((E1,Op,E2)) --> expr(E1),operator(Op),expr(E2).
qui peut être appelé comme Prologue standard.
?- length(Ls,N). Ls = [], N = 0 ; Ls = [_870], N = 1 ; Ls = [_870, _876], N = 2 ; Ls = [_870, _876, _882], N = 3 ; Ls = [_870, _876, _882, _888], N = 4 ; Ls = [_870, _876, _882, _888, _894], N = 5 ; Ls = [_870, _876, _882, _888, _894, _900], N = 6 ...
Une solution étendue utilisant un nombre (1, 2, 3) à n'importe quelle position:
number(1) --> [1]. number(2) --> [2]. operator(+) --> [+]. operator(*) --> [*]. expr(N) --> number(N). expr((E1,Op,E2)) --> operator(Op),expr(E1),expr(E2). expr(E) :- length(Expr,_), phrase(expr(E),Expr).
Exemple d'exécution:
?- expr(E). E = "1+1+1" ; E = "1+1+2" ; E = "1+1+3" ; E = "1+1-1" ; E = "1+1-2" ; E = "1+1-3" ; ...
Pour savoir comment générer avec DCG, consultez cette section Amzi : Génération avec des listes de différences
En commentaire pour une autre réponse, vous avez écrit:
ça ne marche pas plus de 3 éléments? pouvez-vous le développer pour plus d'éléments?
À mesure que le nombre d'éléments augmente, l ' explosion combinatoire augmente également.
Pour limiter l'explosion combinatoire de l'exemple, cela n'utilisera que deux nombres (1,2) et deux opérateurs (+, *), vous pouvez en ajouter plus à votre guise.
number --> [1]. number --> [2]. number --> [3]. operator --> [+]. operator --> [-]. operator --> [*]. operator --> [/]. expr_trinary --> number, operator, number, operator, number. expr(E) :- phrase(expr_trinary,Expr_trinary), atomics_to_string(Expr_trinary,E).
Notez que cela utilise length / 2 pour approfondissement itératif . Fondamentalement, length / 2
génère une liste de longueur croissante puis phrase / 2 propose des réponses de cette longueur.
?- expr_trinary(E,[]). E = [1, +, 2, +, 3] ; E = [1, +, 2, -, 3] ; E = [1, +, 2, *, 3] ; E = [1, +, 2, /, 3] ; E = [1, -, 2, +, 3] ; E = [1, -, 2, -, 3] ; E = [1, -, 2, *, 3] ; E = [1, -, 2, /, 3] ; E = [1, *, 2, +, 3] ; E = [1, *, 2, -, 3] ; E = [1, *, 2, *, 3] ; E = [1, *, 2, /, 3] ; E = [1, /, 2, +, 3] ; E = [1, /, 2, -, 3] ; E = [1, /, 2, *, 3] ; E = [1, /, 2, /, 3].
Pour que le générateur fonctionne comme prévu, le BNF et DCG, par exemple
?- listing(operator). operator([+|A], A). operator([-|A], A). operator([*|A], A). operator([/|A], A). true. ?- listing(expr_trinary). expr_trinary([1|A], B) :- operator(A, C), C=[2|D], operator(D, E), E=[3|B]. true.
qui est récursif gauche direct est converti en ceci
?- expr(E). E = "1+2+3" ; E = "1+2-3" ; E = "1+2*3" ; E = "1+2/3" ; E = "1-2+3" ; E = "1-2-3" ; E = "1-2*3" ; E = "1-2/3" ; E = "1*2+3" ; E = "1*2-3" ; E = "1*2*3" ; E = "1*2/3" ; E = "1/2+3" ; E = "1/2-3" ; E = "1/2*3" ; E = "1/2/3".
Exemple d'exécution:
operator --> [+]. operator --> [-]. operator --> [*]. operator --> [/]. expr_trinary --> [1], operator, [2], operator, [3]. expr(E) :- phrase(expr_trinary,Expr_trinary), atomics_to_string(Expr_trinary,E).
Évalué car il n'y a absolument aucune raison de fournir les opérateurs en tant que faits / prédicats.
une simple récursivité:
list_combine(Ns,Os,Cs) :- [N|Nr] = Ns, member(O,Os), Cs = [N,O|Nt], list_combine(Nr,Os,Nt).
et maintenant
?- forall(list_combine([1,2,3],[+,*],C),writeln(C)). [1,+,2,+,3] [1,+,2,*,3] [1,*,2,+,3] [1,*,2,*,3] true.
voici une - peut-être - une version plus lisible
list_combine([N|Nr],Os,[N,O|Nt]) :- member(O,Os), list_combine(Nr,Os,Nt). list_combine([N],_,[N]).
Bien sûr, utilisez une alternative, juste pour mieux comprendre comment l'unification agit dans la décomposition et la composition des arguments.
Une variante de la belle solution postée par Carlo Capelli nous permet d'illustrer un idiome de programmation utile pour mieux exploiter l'indexation du premier argument:
list_combine([N1| Ns], Os, Nt) :- list_combine(Ns, N1, Os, Nt). list_combine([], N, _, [N]). list_combine([N2| Ns], N1, Os, [N1, O| Nt]) :- member(O, Os), list_combine(Ns, N2, Os, Nt).
L'idée est de passer la liste que nous voulons marchez en séparant la tête de la liste de la queue et passez les deux comme argument avec la queue comme premier argument, comme illustré ci-dessus.
Dans la solution originale, le compilateur Prolog ne fera généralement pas la distinction entre une liste avec un seul élément et une liste avec un ou plusieurs éléments. Mais il fera la distinction entre une liste vide (un atome) et une liste avec au moins un élément (un terme composé). Notez également que la version originale crée un faux point de choix, pour chaque appel récursif, sur l'appel au prédicat list_combine / 3
en plus du point de choix prévu sur le membre / 2
appel de prédicat.
Merci, Paulo. Leçon prise :)
@CapelliC Merci d'avoir ouvert la porte :-)
Cette proposition de ma solution, que je trouve très simple et directe, copiez et collez ci-dessous dans l'éditeur notepad ++ pour obtenir la meilleure lisibilité.
* ________________________________________________ * *|find_expression(NumsList,TargetValue,Expression)| * **------------------------------------------------* * * Expression is an arithmetic expression of the numbers in Numslist with * * possible operators '+','-','*','/' and '(' and ')' between the numbers * * in such a way that the expression evaluates to the TargetValue argument * *****************************************************************************/% /* a single element number list can evaluate only to itself */ find_expression([SingleNumber],SingleNumber,SingleNumber). /* expression of a multypile number list */ find_expression(NumberList,Target,Expression):- /* non-deterministically divide the number list into 2 separate lists which include at least one number each*/ append([X|Xs],[Y|Ys], NumberList), /* recursively find an expression for east list, where the expression evaluates to itself */ find_expression([X|Xs],Exp1,Exp1), find_expression([Y|Ys],Exp2,Exp2), /* non-deterministically choose an operand from [+,-,*,division] and compose Expression to be (Exp1 Operand Exp2) */ ( member(Expression,[Exp1+Exp2,Exp1-Exp2,Exp1*Exp2]) ; /* prevent zero divison */ (Val2 is Exp2, Val2 =\= 0, Expression = (Exp1/Exp2))), %/* /* assure that final expression evaluates(matches) the target value and convert value from integer to float if necessary */ ( Target = Expression ; Target is Expression ; FloatTarget is Target*1.0, FloatTarget is Expression).
Est-ce que
(1 + 2) / 3
est une possibilité, ou1 / (2-3)
?Vous devez expliquer: quelles sont les choses que vous affichez en sortie, par exemple "1 + 2-3"? S'agit-il de termes composés, comme
+ (1, - (2, 3))
ou sont-ils des listes comme[1, +, 2, -, 3]
ou sont-ils juste des atomes ou des chaînes?