Skip to content

Commit

Permalink
refactor: ♻️ Rewrite the type annotations by using typing to make c…
Browse files Browse the repository at this point in the history
…ompatible for Python 3.8
  • Loading branch information
ARCJ137442 committed Sep 26, 2023
1 parent 0cdc809 commit e685b3c
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 127 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
'''Data to NAL
'''Data to Narsese
Define a format for converting Python data structures to Narsese
Core function: <Python data structure>→<NAL **text**>
'''
Core function: <Python data structure>→<Narsese **text**>
'''# compatible type annotation
from typing import List, Dict, Tuple, Union


from pynars.Narsese import Punctuation
from pynars.Narsese import parser
# pynars
Expand Down Expand Up @@ -31,7 +35,7 @@ def is_basic_type(obj: any) -> bool:
return obj == None or t == bool or t == int or t == float or t == str


def verify_term_name(name: str) -> str | None:
def verify_term_name(name: str) -> Union[str,None]:
try:
return (
name
Expand All @@ -44,7 +48,10 @@ def verify_term_name(name: str) -> str | None:


def term_rel(A: str, B: str) -> str:
'''Construct the term "Relationship between A and B"'''
'''
Construct the term "Relationship between A and B
Narsese representation: (*, A, B)
"'''
return f'(*,{A},{B})'


Expand All @@ -66,25 +73,32 @@ def term_name(A: any) -> str:
# sentence construction


def sentence_inh(A: str, B: str, punct: Punctuation | str = Punctuation.Judgement) -> str:
'''Building relationships "A is B"'''
def sentence_inheritance(A: str, B: str, punct: Union[Punctuation,str] = Punctuation.Judgement) -> str:
'''
Building relationships "A is B"
Narsese representation: <A --> B>
'''
return f'<{A} --> {B}>{punct.value if isinstance(punct,Punctuation) else punct}' # <A --> B> default with "."


def sentence_rel(A: str, r: str, B: str, punct: Punctuation = Punctuation.Judgement) -> str:
'''Construct relation "ArB" i.e. "The relation between A and B" is r"'''
return sentence_inh(term_rel(A, B), f'{r}', punct=punct) # <(*,A,B) --> r>. The "relationship" between A and B is r
'''
Construct relation "ArB" i.e. "The relation between A and B" is r"
Narsese representation: <(*, A, B) --> r>
'''
return sentence_inheritance(term_rel(A, B), f'{r}', punct=punct) # <(*,A,B) --> r>. The "relationship" between A and B is r


def sentence_type_sign(name: str, type: type, punct: Punctuation = Punctuation.Judgement) -> str:
'''Name the name based on the type of the object'''
return sentence_inh(name, SIGN_TYPE_NAMES(type), punct=punct) # name --> type
return sentence_inheritance(name, SIGN_TYPE_NAMES(type), punct=punct) # name --> type


def sentence_tri_rel(obj: str, key: str, value: str, relation: str = SIGN_RELATION_OBJ_PROPERTY_VALUE,
punct: Punctuation = Punctuation.Judgement) -> str:
'''Building a ternary relationship "Object [key] = value"
Example: (*,{object},(*,{attribute},{value})) --> object_attribute_value
'''
Building a ternary relationship "Object [key] = value"
Example: <(*,{object},(*,{attribute},{value})) --> object_attribute_value>
'''
return sentence_rel(obj, relation, term_rel(key, value), punct=punct) # (*,{obj},(*,{key},{value})) --> relation

Expand All @@ -94,95 +108,95 @@ def sentence_tri_rel(obj: str, key: str, value: str, relation: str = SIGN_RELATI


# Use kwargs to automatically pass "punctuation" information
def none2NAL(n: None, special_name: str, **kwargs) -> list[str]:
'''None to NAL'''
def none2Narsese(n: None, special_name: str, **kwargs) -> List[str]:
'''None to Narsese'''
return [sentence_type_sign(special_name, type(n), **kwargs)]


def bool2NAL(b: str, special_name: str, **kwargs) -> list[str]:
'''boolean to NAL'''
result: list[str] = [sentence_type_sign(
def bool2Narsese(b: str, special_name: str, **kwargs) -> List[str]:
'''boolean to Narsese'''
result: List[str] = [sentence_type_sign(
special_name, bool, **kwargs)] # preset type identification
return result


def int2NAL(i: int, special_name: str, **kwargs) -> list[str]:
'''Integer to NAL
def int2Narsese(i: int, special_name: str, **kwargs) -> List[str]:
'''Integer to Narsese
TODO: Build an integer system'''
result: list[str] = [sentence_type_sign(
result: List[str] = [sentence_type_sign(
special_name, int, **kwargs)] # preset type identification
return result


def float2NAL(f: float, special_name: str, **kwargs) -> list[str]:
'''Floating-point number becomes NAL
def float2Narsese(f: float, special_name: str, **kwargs) -> List[str]:
'''Floating-point number becomes Narsese
TODO: Build a floating point number system and combine it with an integer system'''
result: list[str] = [sentence_type_sign(
result: List[str] = [sentence_type_sign(
special_name, float, **kwargs)] # preset type identification
return result


def str2NAL(s: str, special_name: str, **kwargs) -> list[str]:
'''Set to NAL
def str2Narsese(s: str, special_name: str, **kwargs) -> List[str]:
'''Set to Narsese
TODO: How does distinguish between "name" and "value" of a string?'''
# tests whether a string can be directly accepted as a term, appended if it is, unappended if it is not
# Try to use the string itself as a name for easy identification
final_name = verify_term_name(s)
final_name: str = special_name + \
(f'「{s}」' if final_name else '') # Include itself if you can, do not add information otherwise
# preset type identification
result: list[str] = [sentence_type_sign(final_name, str, **kwargs)]
result: List[str] = [sentence_type_sign(final_name, str, **kwargs)]
return result

# containers


def set2NAL(s: set, special_name: str, **kwargs) -> list[str]:
'''Set to NAL
def set2Narsese(s: set, special_name: str, **kwargs) -> List[str]:
'''Set to Narsese
Use the relative item "belong"
Import a collection name as the concept name, and then convert all elements within it to NAL
Return: A list of multiple NAL statements (easy to split)'''
result: list[str] = [sentence_type_sign(
Import a collection name as the concept name, and then convert all elements within it to Narsese
Return: A list of multiple Narsese statements (easy to split)'''
result: List[str] = [sentence_type_sign(
special_name, set, **kwargs)] # preset type identification
for item in s: # TODO: Implementing recursive logic @auto2NAL(item)
for item in s: # TODO: Implementing recursive logic @auto2Narsese(item)
result.append(sentence_rel(term_name(item),
SIGN_RELATION_BELONG, special_name, **kwargs))
return result


def lis_tuple2NAL(array: list | tuple, special_name: str, **kwargs) -> List[str]:
'''List/tuple to NAL: Lists whose keys are integers'''
result: list[str] = [sentence_type_sign(
def lis_tuple2Narsese(array: Union[list,tuple], special_name: str, **kwargs) -> List[str]:
'''List/tuple to Narsese: Lists whose keys are integers'''
result: List[str] = [sentence_type_sign(
special_name, type(array), **kwargs)] # preset type identification
for i in range(len(array)):
# get element
item: any = array[i]
iName: str = term_name(i)
item_name: str = term_name(item)
# pre-add definitions for keys and values
result.extend(auto2NAL(item, item_name, **kwargs))
result.extend(auto2NAL(i, iName, **kwargs))
result.extend(auto2Narsese(item, item_name, **kwargs))
result.extend(auto2Narsese(i, iName, **kwargs))
# bind objects, keys, and values
result.append(sentence_tri_rel(
special_name,
iName,
item_name,
**kwargs)) # list[integer_index] = value
**kwargs)) # List[integer_index] = value
return result


def dict2NAL(d: dict, special_name: str, **kwargs) -> list[str]:
'''dict to NAL
#! In fact, JSON is a dictionary, to achieve the dictionary↔NAL conversion, which is equivalent to NARS can read JSON
def dict2Narsese(d: dict, special_name: str, **kwargs) -> List[str]:
'''dict to Narsese
#! In fact, JSON is a dictionary, to achieve the dictionary↔Narsese conversion, which is equivalent to NARS can read JSON
TODO models dictionaries using an index system'''
result: list[str] = [sentence_type_sign(
result: List[str] = [sentence_type_sign(
special_name, dict, **kwargs)] # preset type identification
for key, value in d.items():
key_name: str = term_name(key)
value_name: str = term_name(value)
# pre-add definitions for keys and values
result.extend(auto2NAL(key, key_name, **kwargs))
result.extend(auto2NAL(value, value_name, **kwargs))
result.extend(auto2Narsese(key, key_name, **kwargs))
result.extend(auto2Narsese(value, value_name, **kwargs))
# bind objects, keys, and values
result.append(sentence_tri_rel(
special_name,
Expand All @@ -192,16 +206,16 @@ def dict2NAL(d: dict, special_name: str, **kwargs) -> list[str]:
return result


def type2NAL(t: type, special_name: str, **kwargs) -> list[str]:
'''Type to NAL
The "type" itself also needs to become NAL'''
def type2Narsese(t: type, special_name: str, **kwargs) -> List[str]:
'''Type to Narsese
The "type" itself also needs to become Narsese'''
return [sentence_type_sign(special_name, type, **kwargs)] # only type notations

# default values


def default2NAL(obj: any, special_name: str, **kwargs) -> list[str]:
'''Other objects become NAL
def default2Narsese(obj: any, special_name: str, **kwargs) -> List[str]:
'''Other objects become Narsese
Temporarily occupy the one place, will later be separated from many types'''
print(f'WARNING: unsupported object {obj} with type {type(obj)}')
# only type notations
Expand All @@ -210,31 +224,31 @@ def default2NAL(obj: any, special_name: str, **kwargs) -> list[str]:
# Main function: Integrate all parts #


CONVERT_FUNCTIONS: dict[type:any] = {
type(None): none2NAL,
int: int2NAL,
float: float2NAL,
bool: bool2NAL,
str: str2NAL,
list: lis_tuple2NAL,
tuple: lis_tuple2NAL,
set: set2NAL,
dict: dict2NAL,
type: type2NAL,
None: default2NAL,
CONVERT_FUNCTIONS: Dict[type:any] = {
type(None): none2Narsese,
int: int2Narsese,
float: float2Narsese,
bool: bool2Narsese,
str: str2Narsese,
list: lis_tuple2Narsese,
tuple: lis_tuple2Narsese,
set: set2Narsese,
dict: dict2Narsese,
type: type2Narsese,
None: default2Narsese,
}


def auto2NAL(obj: any, name: str = None, punct: Punctuation = Punctuation.Judgement) -> list[str]:
'''Function integration: Python object →NAL statement sequence
def auto2Narsese(obj: any, name: str = None, punct: Punctuation = Punctuation.Judgement) -> List[str]:
'''Function integration: Python object →Narsese statement sequence
Automatically identify the object type and call the corresponding conversion function'''
# get name
# If no, automatically generate
name = name if name else term_name(obj)
# get type
t = type(obj)
# select & Generate, with default values (all parameters must accept a "Narsese parsed name")
nars_sentences: list[str] = CONVERT_FUNCTIONS.get(
nars_sentences: List[str] = CONVERT_FUNCTIONS.get(
t, CONVERT_FUNCTIONS[None])(obj, name, punct=punct)
# verify
for sentence in nars_sentences:
Expand Down
18 changes: 10 additions & 8 deletions Experiments/ExConsole/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
# other native modules
from random import randint

# compatible type annotation
from typing import List, Dict, Tuple, Union

# information

def show_bag(bag: Bag, sep: str = ',', indent_count: int = 1) -> str:
'''Relation of extension: Channel -> Buffer -> Bag'''
not_none_levels: list[list] = [
not_none_levels: List[list] = [
level_list for level_list in bag.levels if level_list]
if not_none_levels:
sep = sep + '\n' + "\t"*indent_count
Expand Down Expand Up @@ -68,10 +70,10 @@ def show_information():
## Main program ##


EXPERIMENTAL_CMDS: dict[tuple[str]:tuple[any, tuple[str]]] = {}
EXPERIMENTAL_CMDS: Dict[Tuple[str],Tuple[any, Tuple[str]]] = {}


def exp_register(*cmd_names: tuple[str]):
def exp_register(*cmd_names: Tuple[str]):
'''Mimic from `cmd_register` in "Interface.py"
It's no need of parameters because the experimental functions can utilize all of global variable'''
def decorator(func):
Expand Down Expand Up @@ -240,7 +242,7 @@ def chain_inference_test() -> None:
@exp_register('json')
def JSON_test() -> None:
'''Input a series of numbers and construct a set, allowing NARS to determine ownership'''
from data2nal import auto2NAL, SIGN_RELATION_BELONG
from Experiments.ExConsole.data2narsese import auto2NAL, SIGN_RELATION_BELONG
n: int = int(input('Please enter the number: '))
f: set = {x for x in range(n)}
sN: str = f'Num0to{n}'
Expand All @@ -256,7 +258,7 @@ def JSON_test() -> None:
@exp_register('json')
def JSON_test2() -> None:
'''Enter a custom dictionary and ask for relationships one by one'''
from data2nal import auto2NAL
from Experiments.ExConsole.data2narsese import auto2NAL
print('JSON Test Part II:')
dic: dict = {
'smallest_positive_integer': 1,
Expand All @@ -280,7 +282,7 @@ def JSON_test3() -> None:
'''Enter a Config.json object that acts as its own "system parameter"'''
print('JSON Test Part III')
from pynars.Interface import DEFAULT_CONFIG
from data2nal import auto2NAL
from Experiments.ExConsole.data2narsese import auto2NAL
show_information()
execute_input(*auto2NAL(DEFAULT_CONFIG, 'system_config',
punct=Punctuation.Judgement))
Expand All @@ -294,7 +296,7 @@ def JSON_test3() -> None:
@exp_register('eval')
def py_object_load_in() -> None:
'''Load any Python object into NARS'''
from data2nal import auto2NAL
from Experiments.ExConsole.data2narsese import auto2NAL
obj: any = None
while not obj:
try:
Expand All @@ -306,7 +308,7 @@ def py_object_load_in() -> None:
'Please enter a name for this object (leave blank for automatic generation): ')
punct: str = input(
'Please enter your modality for the object (./?/!) (Leave blank default.): ')
nals: list[str] = auto2NAL(
nals: List[str] = auto2NAL(
obj, punct=punct if punct else '.', name=name if name else None)
print(f'Input object: {repr(obj)}\nNAL text: \n' + "\n".join(nals))
execute_input(*nals)
Expand Down
Loading

0 comments on commit e685b3c

Please sign in to comment.