Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better way to type Coconut data types #349

Closed
ArneBachmann opened this issue Nov 1, 2017 · 12 comments
Closed

Better way to type Coconut data types #349

ArneBachmann opened this issue Nov 1, 2017 · 12 comments

Comments

@ArneBachmann
Copy link
Contributor

I wanted to do something like A = TypeVar("A", bound = DA) where data DA(a:int, b:str) but it wasn't allowed to reference the _coconut definitions

@evhub
Copy link
Owner

evhub commented Nov 1, 2017

@ArneBachmann Can you give me a specific piece of code that produces the error you're encountering?

@evhub evhub added the bug label Nov 1, 2017
@evhub evhub added this to the v1.3.2 milestone Nov 1, 2017
@ArneBachmann
Copy link
Contributor Author

ArneBachmann commented Nov 1, 2017

Actual use case was a copy-constructor for data types. This didn't work:

from typing import Type, TypeVar
data BranchInfo(number:int, ctime:int, name:str? = None, tracked:str[] = [])
try: BI = TypeVar("BI", bound = BranchInfo)  # only valid for Python 3
except: pass
def dataCopy(tipe:Type[BI], old:BI, **kwargs): r = old._asdict(); r.update(**kwargs); return tipe(**r)

Unsupported type Type["BranchInfo"]

but this did:

from typing import Type, TypeVar
data BranchInfo(number:int, ctime:int, name:str? = None, tracked:str[] = [])
try: BI = TypeVar("BI", bound = BranchInfo)  # only valid for Python 3
except: pass
def dataCopy(tipe:Type[BI], old:BI, **kwargs): r = old._asdict(); r.update(**kwargs); return makedata(tipe, **r)

<no mypy complaints>

The only change is using makedata instead of calling the constructor.

But in this code, I have to pin the copy function to a certain data type, instead of to generic data types.

@ArneBachmann
Copy link
Contributor Author

ArneBachmann commented Nov 2, 2017

Found a generic workaround that doesn't complain in mypy and runs with any namedtuple (problem is that namedtuple is a runtime code-generator factory):

import collections
from typing import Type, TypeVar

class _AsDict(tuple):
  def _asdict(_) -> collections.OrderedDict: pass  # type hinting for mypy

try: DataType = TypeVar("DataType", bound = _AsDict)
except: pass  # Python 2 mypy

def dataCopy(tipe:Type[DataType], old:DataType, **kwargs) =
  r = old._asdict()
  r.update(**kwargs)
  makedata(tipe, *[r[field] for field in old._fields])  # **r doesn't work, only positional arguments allowed :-(

@ArneBachmann
Copy link
Contributor Author

Exposing something like above _AsDict as CoconutDataType and/or coconut_typing.DataType would close probably this issue.

@ArneBachmann
Copy link
Contributor Author

Current solution focusing purely on Python 3:

from typing import Type, TypeVar
DataType = TypeVar("DataType", MergeBlock, BranchInfo)  # list all your types here
def dataCopy(_tipe:Type[DataType], _old:DataType, *_args, **_kwargs) -> DataType: r = _old._asdict(); r.update(**_kwargs); return makedata(_tipe, *(list(_args) + [r[field] for field in _old._fields]))

@evhub
Copy link
Owner

evhub commented Nov 22, 2017

@ArneBachmann I see what's going on here. What you should do is just use typing.NamedTuple exactly how you would use a CoconutDataType. I'm thinking one nice way to resolve this might be to support turning the keyword data in a type definition into _coconut_NamedTuple, which would fix the issue.

@evhub evhub added modification and removed bug labels Nov 22, 2017
@ArneBachmann
Copy link
Contributor Author

If every data type was a namedtuple, it might work, is that what you mean as well? I'm looking for a way to type check data/named tuples generically as seen in the function above

@evhub
Copy link
Owner

evhub commented Nov 23, 2017

@ArneBachmann From MyPy's perspective, all data types should look like named tuples.

@ArneBachmann
Copy link
Contributor Author

OK I don't get it. Can you provide a minimal example on how to typecheck them datat ypes in Coco --mypy?

@evhub
Copy link
Owner

evhub commented Nov 25, 2017

@ArneBachmann For example:

~\Documents\GitHub> co --mypy
Coconut Interpreter:
(type 'exit()' or press Ctrl-D to end)
>>> try: from typing import NamedTuple
    except: pass

>>> data vec(x, y)
>>> data intvec(x: int, y: int)
>>> def scale(s: int, v: NamedTuple) = v |> fmap$(-> _*s)
>>> vec(1, 1) |> scale$(2)
vec(x=2, y=2)
>>> intvec(1, 1) |> scale$(2)
intvec(x=2, y=2)

As you can see, both untyped (vec) and typed (intvec) data types are, for the purposes of type-checking, of type typing.NamedTuple. Note that the typing import need not succeed for this to work--MyPy will still know what you mean even if it doesn't.

@ArneBachmann
Copy link
Contributor Author

That doesn´t work... I cannot simply replace any data type with a NamedTuple. Also I want to ensure the function´s output is the same NamedTuple type, not just any one.

error: Incompatible types in assignment (expression has type "NamedTuple", variable has type "ChangeSet")

@evhub evhub changed the title How to reference _coconut_NamedTuple in user code? Better way to type Coconut data types Jan 18, 2018
@evhub evhub modified the milestones: v1.3.2, v1.4.0 Mar 26, 2018
@evhub
Copy link
Owner

evhub commented Jul 31, 2020

@ArneBachmann Not sure what changed, but it looks like this is just working now, so I'm closing this issue:

> co -t sys --mypy                                                                            Coconut Interpreter:
(enter 'exit()' or press Ctrl-D to end)
>>> data vec(x, y)
Success: no issues found in 1 source file
>>> def f(v: vec) = v
Success: no issues found in 1 source file
>>> f(vec(1, 2))
vec(x=1, y=2)
Success: no issues found in 1 source file
>>>

@evhub evhub closed this as completed Jul 31, 2020
@evhub evhub added the resolved label Jul 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants