Let's say we have four properties :
ObjectProperty: superProp1
InverseOf: superProp3
ObjectProperty: prop1
InverseOf: prop2
SubPropertyOf:superProp1
ObjectProperty: prop2
InverseOf: prop1
ObjectProperty: superProp3
Pellet deduces that prop2 is a subproperty of superProp3.
I can't understand this result.
Assuming :a :prop2 :b, one can infer that :a :superProp3 :b (for any :a and :b):
Let's suppose that :a :prop2 :b.
Then :b :prop1 :a holds, because :prop2 is an inverse of :prop1.
Then :b :superProp1 :a holds, because :prop1 is a subproperty of :superProp1.
Then :a :superProp3 :b holds, because :superProp1 is an inverse of :superProp3.
Slightly more formally:
T1. :a :prop1 :b <=> :b prop2 :a # :prop1 owl:inverseOf :prop2
T2. :a :prop1 :b => :a :superProp1 :b # :prop1 rdfs:subPropertyOf :superProp1
T3. :a :superProp1 :b <=> :b :superProp3 :a # :superProp1 owl:inverseOf :superProp3
A1. :a :prop2 :b # assumption, eliminated by T4
A2. :b :prop1 :a # A1, T1, modus ponens
A3. :b :superProp1 :a # A2, T2, modus ponens
A4. :a :superProp3 :b # A3, T3, modus ponens
T4. :a :prop2 :b => :a :superProp3 :b # A1, A4, deduction theorem; QED
More info:
9.2.1 Object Subproperties
9.2.4 Inverse Object Properties
Maybe using less abstract naming can give you a feeling of what's going on. Lets consider the same problem described using words having a semantic.
We know the following rules :
Being Wet is the inverse of being Dry.
It exist another kind of wetness, ReallyWet. Being ReallyWet always imply you're Wet, thus it is a subproperty of Wet.
Finally, we also know that being ReallyWet is the opposite of being ReallyDry.
From this you -and pellet- can then conclude that ReallyDry is a kind of dryness.
Why ? The reasoning is :
Dry is the inverde of Wet
ReallyDry is the inverse of ReallyWet
ReallyWet is a subproperty of Wet
->
ReallyDry is the inverse of a subproperty of Wet, and as such is should be the subproperty of the inverse of Wet. Conclusion : ReallyWet is a subproperty of Wet.
Does it sound logic ? I think that pellet can explain the rule it used to deduce some triples.
It probably is :
( A inverse of B ) AND
( C inverse of D ) AND
(C is a sub property of A) ->
D is a sub property of B
Related
For example 1 :
Classes : A and B.
Property : hasValue.
Axiom : hasValue some A disjointWith hasValue some B.
Individual : user1.
user1 hasValue A.
user1 hasValue B.
Protege reasoner (HermiT) throws no error.
For example 2 :
Classes : A and B.
A disjoint with B.
Property : hasValue.
Axiom : hasValue some A disjointWith hasValue some B.
Individual : user1.
user1 hasValue A.
user1 hasValue B.
Protege reasoner (HermiT) throws error.
Shouldn't "hasValue some A disjointWith hasValue some B" alone be sufficient to throw error in eg 1's case?
EDIT : example 1's reasoner result is wrong. As #Henriette Harmse showed below reasoner will throw error.
I was doing declaring Axiom a little differently than what I wrote above. I declared axiom as "hasValue some B DisjointWith hasValue some
(P and (not (B)))", where P is parent class of both A and B. (Full sample ontology below.) If you import it in protege and run, you'll not get error.
It seems :
"hasValue some B DisjointWith hasValue some A"
"hasValue some B DisjointWith hasValue some (P and (not (B)))"
are not equivalent statements.
Sample ontology :
#prefix : <http://test.org/#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix xml: <http://www.w3.org/XML/1998/namespace> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#base <http://test.org/> .
<http://test.org/> rdf:type owl:Ontology .
#################################################################
# Object Properties
#################################################################
### http://test.org/#hasValue
:hasValue rdf:type owl:ObjectProperty .
#################################################################
# Classes
#################################################################
### http://test.org/#A
:A rdf:type owl:Class ;
rdfs:subClassOf :P .
### http://test.org/#B
:B rdf:type owl:Class ;
rdfs:subClassOf :P .
### http://test.org/#P
:P rdf:type owl:Class .
### http://test.org/#USER
:USER rdf:type owl:Class .
#################################################################
# Individuals
#################################################################
### http://test.org/#A
:A rdf:type owl:NamedIndividual ,
:A .
### http://test.org/#B
:B rdf:type owl:NamedIndividual ,
:B .
### http://test.org/#user1
:user1 rdf:type owl:NamedIndividual ;
:hasValue :A ,
:B .
#################################################################
# General axioms
#################################################################
[ rdf:type owl:Restriction ;
owl:onProperty :hasValue ;
owl:someValuesFrom :A ;
owl:disjointWith [ rdf:type owl:Restriction ;
owl:onProperty :hasValue ;
owl:someValuesFrom [ owl:intersectionOf ( :P
[ rdf:type owl:Class ;
owl:complementOf :A
]
) ;
rdf:type owl:Class
]
]
] .
[ rdf:type owl:Restriction ;
owl:onProperty :hasValue ;
owl:someValuesFrom :B ;
owl:disjointWith [ rdf:type owl:Restriction ;
owl:onProperty :hasValue ;
owl:someValuesFrom [ owl:intersectionOf ( :P
[ rdf:type owl:Class ;
owl:complementOf :B
]
) ;
rdf:type owl:Class
]
]
] .
### Generated by the OWL API (version 4.5.9.2019-02-01T07:24:44Z) https://github.com/owlcs/owlapi
I have tried this now myself and for your first example I get an inconsistency with the following explanation:
Here is the actual ontology giving the inconsistency. I will need to see your actual ontology to understand why you are not getting an inconsistency.
<?xml version="1.0"?>
<rdf:RDF xmlns="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#"
xml:base="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:untitled-ontology-9="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#">
<owl:Ontology rdf:about="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9"/>
<owl:ObjectProperty rdf:about="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#hasValue"/>
<owl:Class rdf:about="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#A"/>
<owl:Class rdf:about="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#B"/>
<owl:NamedIndividual rdf:about="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#a">
<rdf:type rdf:resource="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#A"/>
</owl:NamedIndividual>
<owl:NamedIndividual rdf:about="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#b">
<rdf:type rdf:resource="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#B"/>
</owl:NamedIndividual>
<owl:NamedIndividual rdf:about="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#user1">
<hasValue rdf:resource="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#a"/>
<hasValue rdf:resource="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#b"/>
</owl:NamedIndividual>
<owl:Restriction>
<owl:onProperty rdf:resource="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#hasValue"/>
<owl:someValuesFrom rdf:resource="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#A"/>
<owl:disjointWith>
<owl:Restriction>
<owl:onProperty rdf:resource="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#hasValue"/>
<owl:someValuesFrom rdf:resource="http://www.semanticweb.org/henri/ontologies/2022/6/untitled-ontology-9#B"/>
</owl:Restriction>
</owl:disjointWith>
</owl:Restriction>
</rdf:RDF>
Update after reviewing ACTUAL ontology
The main problem is that you stated the GCI you used incorrectly. What you said you used are substantially different from what you actually used.
What you said used: hasValue some A disjointWith hasValue some B
What you actually used:
hasValue some A DisjointWith hasValue some (P and (not (A)))
hasValue some B DisjointWith hasValue some (P and (not (B)))
To understand why your GCIs do not have the desired effect, I have drawn an example Venn diagram:
Note that hasValue some A DisjointWith hasValue some (P and (not (A))) states that there is no individual x that belongs to both the set hasValue some A and the set hasValue some (P and (not (A))). It does however allow for the possibility that you have an individual user1 that is related via hasValue to an individual in set A and that is related via hasValue to an individual in set B. This is because nothing prohibits the sets hasValue some A (to which user1 hasValue A belongs) and hasValue some B (to which user1 hasValue B belongs)` to overlap. To prohibit this, you have to add the following GCI:
hasValue some A DisjointWith hasValue some B
How to get a inconsistency using you GCIs
To get an inconsistency using your GCIs, you have to have an individual that actually belong to the disjoint sets you defined. I.e.,
Define individual x as follows:
:x rdf:type owl:NamedIndividual ,
[ owl:intersectionOf ( :P
[ rdf:type owl:Class ;
owl:complementOf :A
]
) ;
rdf:type owl:Class
] .
and then define user2:
:user2 rdf:type owl:NamedIndividual ;
:hasValue :A ,
:x .
You will get an inconsistency with the following explanation:
This question already has answers here:
How to iterate over an array using indirect reference?
(7 answers)
Closed 3 years ago.
I'd like to use arrays in BASH properly when using indirection ${!varname}.
Here's my sample script:
#!/bin/bash
i="1 2 3"
x=CONFIG
y1=( "A and B" "B and C" )
# y1=( "\"A and B\"" "\"B and C\"" )
y2=( "ABC and D" )
y3=
echo "y1=${y1[#]}"
echo "y2=${y2[#]}"
echo "y3=${y3[#]}"
echo "==="
for z in $i
do
t=y${z}
tval=( ${!t} )
r=0
echo "There are ${#tval[#]} elements in ${t}."
if [ ${#tval[#]} -gt 0 ]; then
r=1
echo "config_y${z}=\""
fi
for tv in "${tval[#]}"
do
[ -n "${tv}" ] && echo "${tv}"
done
if [ "x$r" == "x1" ]; then
echo "\""
fi
done
Here's the result:
y1=A and B B and C
y2=ABC and D
y3=
===
There are 3 elements in y1.
config_y1="
A
and
B
"
There are 3 elements in y2.
config_y2="
ABC
and
D
"
There are 0 elements in y3.
What I would like to get instead is:
y1=A and B B and C
y2=ABC and D
y3=
===
There are 2 elements in y1.
config_y1="
A and B
B and C
"
There are 1 elements in y2.
config_y2="
ABC and D
"
There are 0 elements in y3.
I also tried to run something like this:
#!/bin/bash
i="1 2 3"
x=CONFIG
y1=( "A and B" "B and C" )
# y1=( "\"A and B\"" "\"B and C\"" )
y2=( "ABC and D" )
y3=
for variable in ${!y#}
do
echo "$variable" # This is the content of $variable
echo "${variable[#]}" # So is this
echo "${!variable}" # This shows first element of the indexed array
echo "${!variable[#]}" # Not what I wanted
echo "${!variable[0]} ${!variable[1]}" # Not what I wanted
echo "---"
done
Ideally, ${!Variable[#]} should do what I want, but it doesn't.
Also, ${!Variable} only shows the first element of the array,
What can I try?
Your syntax for accessing arrays is wrong here:
tval=( ${!t} )
This will evaluate to e.g. $y1 but you want "${y1[#]}" which is how you address an array with that name with proper quoting.
Unfortunately, there is no straightforward way to refer to an array through indirection, but see Indirect reference to array values in bash for a couple of workarounds.
Notice also how
y3=()
is different from
y3=
Using variables for stuff which isn't actually variable is a bit of a code smell, too.
#!/bin/bash
i="1 2 3"
x=CONFIG
y1=( "A and B" "B and C" )
y2=( "ABC and D" )
# Fix y3 assignment
y3=()
echo "y1=${y1[#]}"
echo "y2=${y2[#]}"
echo "y3=${y3[#]}"
echo "==="
for z in $i
do
# Add [#] as in Aaron's answer to the linked question
t=y${z}[#]
# And (always!) quote the variable interpolation
tval=( "${!t}" )
r=0
echo "There are ${#tval[#]} elements in ${t}."
if [ ${#tval[#]} -gt 0 ]; then
r=1
echo "config_y${z}=\""
fi
for tv in "${tval[#]}"
do
[ -n "${tv}" ] && echo "${tv}"
done
if [ "x$r" = "x1" ]; then
echo "\""
fi
done
Probably also investigate printf for unambiguously printing values.
I have an object property partOf which is transitive.
And I want to say that:
a partOf Year then a is a Term
b partOf Term then b is a Course
And simultaneously:
a partOf Knowledge_Group then a is a Knowledge_Area
b partOf Knowledge_Area then b is a Course
For that I'm using this to say b partOf Term or Knowledge_Area then b is a Course:
:Course rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :partOf ;
owl:someValuesFrom [ rdf:type owl:Class ;
owl:unionOf ( :Knowledge_Area
:Term
)
]
] .
But when I run the reasoner I get all the courses listed as instances of the class Term and same for Knowledge_Area:
If I don't use the or and set that Course is equivalent only to partOf some Term or partOf some Knowledge_Area (separately and one at a time) I don't get this issue.
Is there a way I can say what I explained at the beginning and not get the courses inferred to be of type Term?
Here there is a minimal example:
#prefix : <http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#> .
#prefix owl: <http://www.w3.org/2002/07/owl#> .
#prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
#prefix xml: <http://www.w3.org/XML/1998/namespace> .
#prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
#prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
#base <http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27> .
<http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27> rdf:type owl:Ontology .
#################################################################
# Object Properties
#################################################################
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#partOf
:partOf rdf:type owl:ObjectProperty ,
owl:TransitiveProperty .
#################################################################
# Classes
#################################################################
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Course
:Course rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :partOf ;
owl:someValuesFrom [ rdf:type owl:Class ;
owl:unionOf ( :Knowledge_Area
:Term
)
]
] .
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Knowledge_Area
:Knowledge_Area rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :partOf ;
owl:someValuesFrom :Knowledge_Group
] .
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Knowledge_Group
:Knowledge_Group rdf:type owl:Class ;
owl:disjointWith :Year .
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Term
:Term rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :partOf ;
owl:someValuesFrom :Year
] .
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Year
:Year rdf:type owl:Class .
#################################################################
# Individuals
#################################################################
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Course_1
:Course_1 rdf:type owl:NamedIndividual ;
:partOf :Knowledge_Area_1 ,
:Term_1 .
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Knowledge_Area_1
:Knowledge_Area_1 rdf:type owl:NamedIndividual ;
:partOf :Knowledge_Group_1 .
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Knowledge_Group_1
:Knowledge_Group_1 rdf:type owl:NamedIndividual ,
:Knowledge_Group .
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Term_1
:Term_1 rdf:type owl:NamedIndividual ;
:partOf :Year_1 .
### http://www.semanticweb.org/lucia/ontologies/2018/5/untitled-ontology-27#Year_1
:Year_1 rdf:type owl:NamedIndividual ,
:Year .
### Generated by the OWL API (version 4.2.8.20170104-2310) https://github.com/owlcs/owlapi
The semantics of transitive roles are if (x, y) \in R and (y, z) \in R then (x, z) \in R. Based on this from your ontology you have that:
(1) Course_1 partOf Knowledge_Area_1 partOf Knowledge_Group_1 which means Course_1 partOf Knowledge_Group_1 which is equivalent to Knowledge_Area.
(2) Course_1 partOf Term_1 partOf partOf Year_1 which means Course_1 partOf Year_1 which is equivalent to Term.
Hence Course_1 is a Term and a Knowledge_Area and since Course is equivalent to Term or Knowledge_Area, Course_1 is also a Course, which is pretty much what an explanation says for why Course_1 is a Term.
In my opinion the key thing to realize here is that you in actual fact are dealing with different partOf relations, not a single one. The clue to this fact is that in different contexts you want to infer different type information from your partOf relation. Type information from relations in OWL is inferred mostly from domain and range restrictions. Here is a possible solution to your problem:
ObjectProperty: partOf
ObjectProperty: partOfKA
SubPropertyOf: partOf
Domain: Course
ObjectProperty: partOfKG
SubPropertyOf: partOf
Domain: Knowledge_Area
ObjectProperty: partOfTerm
SubPropertyOf: partOf
Domain: Course
ObjectProperty: partOfYear
SubPropertyOf: partOf
Domain: Term
Class: Course
Class: Knowledge_Area
Class: Knowledge_Group
DisjointWith: Year
Class: Term
Class: Year
DisjointWith: Knowledge_Group
Individual: Course_1
Facts:
partOfKA Knowledge_Area_1,
partOfTerm Term_1
Individual: Knowledge_Area_1
Facts: partOfKG Knowledge_Group_1
Individual: Knowledge_Group_1
Types: Knowledge_Group
Individual: Term_1
Facts: partOfYear Year_1
Individual: Year_1
Types: Year
Strictly speaking you do not need the partOf property in my example ontology. I merely added it for conceptual clarity. Moreover, in my example ontology there is no need for transitive properties.
I want to design an object property which is always linked only between the same level of classes. For example,
I want to limit the property isCounterPartOf to be an arc of the sibling nodes which belong to the same upper class, such as
house isCounterPartOf cars
bad isCounterPartOf good
slow isCounterPartOf fast
and the property should NOT link between classes of different levels (those having different ancestors), like
cars isCounterPartOf bad
cars isCounterPartOf object
cars isCounterPartOf Entity
Is there a way to do this with defining only one property?
Assuming your objective is when :isCounterPartOf links two individuals, and one is a member of e.g. :Bad, then the other should be classified as :Good, you don't need to define domain and range of :isCounterPartOf, just that it is owl:SymmetricProperty. You only need to define your classes, :Bad to be equivalent of :isCounterPartOf some :Good and :Good to be equivalent of :isCounterPartOf some :Bad, and for all "pairs" of classes respectively.
Then if:
:A :isCounterPartOf :B
:C :isCounterPartOf :B
:A a :Slow
:C a :Bad
then :B will be classified as :Fast and :Good.
Clarification (based on the comments)
In the example above,
1. :isCouterPartOf is a symetric object property:
:isCounterPartOf rdf:type owl:ObjectProperty ,
owl:SymmetricProperty .
:Good, :Bad, :Slow and :Fast are OWL classes, for which:
(no idea why the code formatting doesn't work)
:Bad rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :isCounterPartOf ;
owl:someValuesFrom :Good
] .
:Fast rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :isCounterPartOf ;
owl:someValuesFrom :Slow
] .
:Good rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :isCounterPartOf ;
owl:someValuesFrom :Bad
] .
:Slow rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :isCounterPartOf ;
owl:someValuesFrom :Fast
] .
:A, :B, and :C are individuals, for which it is asserted that:
(again, no idea why the code formatting doesn't work)
:A rdf:type owl:NamedIndividual ,
:Slow ;
:isCounterPartOf :B .
:B rdf:type owl:NamedIndividual ,
owl:Thing .
:C rdf:type owl:NamedIndividual ,
:Bad ;
:isCounterPartOf :B .
Based on these assertions, when you run the reasoner, you'll have the following situation:
:A rdf:type owl:NamedIndividual ,
:Bad , #inferred
:Slow ;
:isCounterPartOf :B .
:B rdf:type owl:NamedIndividual ,
:Fast , #inferred
:Good , #inferred
owl:Thing ;
:isCounterPartOf :A , #inferred
:C . #inferred
:C rdf:type owl:NamedIndividual ,
:Bad ,
:Slow ; #inferred
:isCounterPartOf :B .
Suppose I have an array foo that looks like the below, notice the third element.
foo=("a" "b" "c c")
echo "${foo[2]}" # "c c"
echo "${#foo[#]}" # "3"
How might I create an exact duplicate of that array into a variable bar?
And then if you want to pass that array (by value) into a function baz?
Edit: Moved answer to answer.
If you want to pass an array by reference (which is what your code actually does), bash 4.3 allows this to be done with namevars:
foo=( hello "cruel world" )
print_contents() {
local -n array=$1
printf '%q\n' "${array[#]}"
}
print_contents foo
If you want to pass by value, even easier (and functional even with ancient releases):
foo=( hello "cruel world" )
print_contents() {
printf '%q\n' "$#"
}
print_contents "${foo[#]}"
If you want to pass multiple arrays by value, by contrast:
foo=( hello "cruel world" )
bar=( more "stuff here" )
print_arrays() {
while (( $# )); do
printf '%s\n' "Started a new array:"
local -a contents=()
local array_len
array_len=$1; shift
for ((n=0; n<array_len; n++)); do
contents+=( "$1" ); shift
done
printf ' %q\n' "${contents[#]}"
done
}
print_arrays "${#foo[#]}" "${foo[#]}" \
"${#bar[#]}" "${bar[#]}"
I ended up finding my answer as I was writing the question. Here's the train of thought.
Several attempts below
bar=foo # String "foo"
bar=$foo # First element of array foo "a"
bar=${foo[#]}
echo "${#bar[#]}" # "1"
echo "${bar[0]}" # "a b c c"
bar=(${foo[#]})
echo "${#bar[#]}" # "4"
echo "${bar[2]}" # "c"
echo "${bar[3]}" # "c"
bar=("${foo[#]}")
echo "${#bar[#]}" # "3"
echo "${bar[2]}" # "c c"
baz () {
eval "bar=(\"\${$1[#]}\")"
for item in "${bar[#]}"
do
echo "$item"
done
# a
# b
# c c
}
function baz {
set $1[#]
printf '%s\n' "${!1}"
}
foo=(a b 'c c')
bar=("${foo[#]}")
baz bar