# Forall and a terminology question

**URL:** <https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630>\
**Category:** Help!\
**Created:** [June 11, 2023, 8:32pm UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630 "2023-06-11T20:32:20Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [June 11, 2023, 8:32pm UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/1 "2023-06-11T20:32:20Z")

</div>

Assuming we establish

```prolog
length(L,Len), between(1, Len, N)

```

Then we further require:

```prolog
nth1(N, L, N)

```

What terminology do we use to discuss `L` where:

```prolog
L=[A,A,A] % L can be solved for any N

```

vs `L` where:

```prolog
L=[A,B,C] % L can be solved to satisfy all N simultaneously?

```

Given the above, (and the latter `L = [A,B,C]`)) what’s the idiomatic way to get `L=[1,2,3]`?

I can do:

```prolog
findall(L,nth1(N,L,N), Ls), unified([L|Ls]).

unified([]).
unified([_]).
unified([X, X | T]) :- unified([X | T]).

```

I can not seem to get the above effect with any of forall,findall,bagof.

Edit:  
Important clarifications added here:

> [@Forall and a terminology question](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/5):
>
> @brebs My example used a list. But I don’t need a list (or numbers) per se. Let me clarify further. I asked What terminology do we use to discuss L where … it can be solved for any N … it can be solved to satisfy all N simultaneously Bold is to highlight the concept I’m interested in. My other question was: Given the above, (and the latter L = [A,B,C] )) what’s the idiomatic way to get L=[1,2,3] ? My question (deliberately) was not “how do I get a list of numbers”. I’m interested …

---

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [June 12, 2023, 4:39am UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/2 "2023-06-12T04:39:41Z")

</div>

> [@z5h](#):
>
> `length(L,Len), range(1, Len, N)`

Is the “range/3” a builtin ? It seems no doc for it in the SWIPL manual.

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [June 12, 2023, 5:28am UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/3 "2023-06-12T05:28:30Z")

</div>

Should have been between. Had some other language stuck in my head apparently. Fixed.

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [June 12, 2023, 6:57am UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/4 "2023-06-12T06:57:23Z")

</div>

Sounds like you want a bit more than numlist/3 provides:

```prolog
% Like numlist but with variable Upper, starting from 1
range1(Upper, [1|Lst]) :-
    ( nonvar(Upper)
    -> integer(Upper),
        Upper @>= 1
    ; var(Upper)
    ),
    range1_(Lst, 1, Upper).

range1_([], Lower, Upper) :-
    ( Lower == Upper
    -> !
    ; Lower = Upper
    ).
range1_([Lower1|Lst], Lower, Upper) :-
    Lower1 is Lower + 1,
    range1_(Lst, Lower1, Upper).

```

```prolog
?- range1(N, L).
N = 1,
L = [1] ;
N = 2,
L = [1, 2] ;
N = 3,
L = [1, 2, 3] ;

?- range1(3, L).
L = [1, 2, 3].

?- length(L, 3), range1(N, L).
L = [1, 2, 3],
N = 3.

```

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [June 12, 2023, 1:14pm UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/5 "2023-06-12T13:14:31Z")

</div>

@brebs

My example used a list. But I don’t need a list (or numbers) per se.  
Let me clarify further.

I asked

> What terminology do we use to discuss `L` where  
> … it can be solved for **any N**  
> … it can be solved to satisfy **all N simultaneously**

Bold is to highlight the concept I’m interested in.

My other question was:

> Given the above, (and the latter `L = [A,B,C]` )) what’s the idiomatic way to get `L=[1,2,3]` ?

My question (deliberately) was not “how do I get a list of numbers”.

I’m interested in the abstract notion of **unifying a term to satisfy any valid constraint** , vs **all valid constraints simultaneously** , with respect to some constraint.

I could have asked, given the above, AND the following:

```prolog
name_key(surname).
name_key(forename).
name_key(middlename).

funny_word("Clown").
funny_word("Joker").

funny_name(FirstName, MiddleName, LastName, NameKey) :-
    (NameKey = surname, funny_word(LastName)); 
    (NameKey = forename, funny_word(FirstName));
    (NameKey = middlename, funny_word(MiddleName)).

```

What is the idiomatic “thing” that does:

```prolog
solved_all(..., funny_name(FirstName, MiddleName, LastName, NameKey), ...)
solved_all(..., nth1(N,L,N), ...)

```

and gives me

```prolog
FirstName="Clown" MiddleName="Clown" LastName="Clown"; 
FirstName="Clown" MiddleName="Clown" LastName="Joker"; 
... etc

```

and

```prolog
[1,2,3].

```

---

<div class="post-metadata">

**Author:** ![oskardrums](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/oskardrums/32/3594_2.png) [@oskardrums](https://swi-prolog.discourse.group/u/oskardrums)\
**Post date:** [June 12, 2023, 1:53pm UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/6 "2023-06-12T13:53:55Z")

</div>

> [@z5h](#):
>
> I’m interested in the abstract notion of **unifying a term to satisfy any valid constraint** , vs **all valid constraints simultaneously** , with respect to some constraint.

This is not quite clear.  
Prolog finds variable substitutions that satisfy the goal you give it. If you have multiple goals and you want the substitution to satisfy all them simultaneously, use conjunction (`,/2`). If you want it to satisfy at least one goal, use disjunction (`;/2` or multiple clauses).  
Does that make sense?

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [June 12, 2023, 2:32pm UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/7 "2023-06-12T14:32:46Z")

</div>

Well, I can find what I’m looking for, in Prolog, whatever it’s called. I’m asking for help in the terminology that clarifies this. So I’m not surprised it isn’t yet clear.

I gave the example with the list that returns `[1,2,3]`.

The funny name example doesn’t quire work out as stated. My bad. The following does find “Clown” “Clown” to be the the funny name regardless of which name\_key is used:

```prolog
name_key(surname).
name_key(forename).

funny_word("Clown").

funny_name(FirstName, LastName, NameKey) :-
    (NameKey = surname, funny_word(LastName)); 
    (NameKey = forename, funny_word(FirstName)).
    
name_example(FirstName, LastName) :- 
    findall((First, Last), (name_key(NameKey), funny_name(First, Last, NameKey)) , Ls),
    unified([(FirstName, LastName)|Ls]). 

```

---

<div class="post-metadata">

**Author:** ![oskardrums](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/oskardrums/32/3594_2.png) [@oskardrums](https://swi-prolog.discourse.group/u/oskardrums)\
**Post date:** [June 12, 2023, 2:53pm UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/8 "2023-06-12T14:53:40Z")

</div>

The way I read your definition of funny\_name/3, it says that “a full name is funny if either the first name is funny or the last name is funny”.  
FWIW I’d define it as:

```prolog
funny_name(FirstName, _) :- funny_word(FirstName).
funny_name(_, LastName) :- funny_word(LastName).

```

I understand that you’re looking for `FirstName = "Clown", LastName = "Clown"`. What I don’t understand is why you can’t use a conjuction to obtain it, i.e.:

```prolog
funny_name(FirstName, LastName) :- 
    funny_word(FirstName),
    funny_word(LastName).

```

Then:

```prolog
?- funny_name(FirstName, LastName).
FirstName = LastName, LastName = "Clown".

```

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [June 12, 2023, 3:24pm UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/9 "2023-06-12T15:24:52Z")

</div>

> [@oskardrums](#):
>
> What I don’t understand is why you can’t use a conjuction to obtain

It’s putting the cart before the horse.

I’m not trying to build a list or find a name. These are examples.  
Maybe putting it another way will help.  
I want to know, if **given** `A1 \/ A2 \/ ... An ... ==> B` is there a **way of finding** `(A1 ... An)` such that `A1 /\ A2 /\ ... /\ An`?

---

<div class="post-metadata">

**Author:** ![firefrorefiddle](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/firefrorefiddle/32/4619_2.png) [@firefrorefiddle](https://swi-prolog.discourse.group/u/firefrorefiddle)\
**Post date:** [October 11, 2023, 10:29am UTC](https://swi-prolog.discourse.group/t/forall-and-a-terminology-question/6630/12 "2023-10-11T10:29:07Z")

</div>

It seems to me that you asked for `foreach/2`:

```prolog
?- length(L,Len), foreach(between(1,Len,N),nth1(N,L,N)).
L = [],
Len = 0 ;
L = [1],
Len = 1 ;
L = [1, 2],
Len = 2 ;
L = [1, 2, 3],
Len = 3 ;
L = [1, 2, 3, 4],
Len = 4 ;
L = [1, 2, 3, 4, 5],
Len = 5 ;
L = [1, 2, 3, 4, 5, 6],
Len = 6 ;
L = [1, 2, 3, 4, 5, 6, 7],
Len = 7 

?- L=[A,A,A], length(L,Len), foreach(between(1,Len,N),nth1(N,L,N)).
false.

?- L=[A,B,C], length(L,Len), foreach(between(1,Len,N),nth1(N,L,N)).
L = [1, 2, 3],
A = 1,
B = 2,
C = Len, Len = 3.

```

For the name example - in the real world this would of course be much simpler:

```prolog
funny_word("Clown").
funny_word("Joker").

name_example(FirstName, LastName) :- 
    funny_word(FirstName),
    funny_word(LastName).

```

But for the sake of the question I think you look for something like this:

```prolog

name_key(surname).
name_key(forename).

has_name(Key,Value,Names) :-
    member(Key-Value, Names).

names(Names) :-
    foreach(name_key(Key),
	    (
		funny_word(Name),		
		has_name(Key,Name,Names)	    
	    )).

```

Example:

```prolog
?- length(N,_), names(N).
N = [surname-"Clown", forename-"Clown"] ;
N = [forename-"Clown", surname-"Clown"] ;
N = [surname-"Joker", forename-"Joker"] ;
N = [forename-"Joker", surname-"Joker"] 

```

(Note that you need the `has_name/3` predicate or something similar, because just plugging in `member(Key-Name,Names)` doesn’t work: [Foreach bug?](https://swi-prolog.discourse.group/t/foreach-bug/4684)
