def test_local_definitions():
    # Taken from the paper 'Practical type inference for arbitrary-rank types'
    # by Peyton Jones, Simon et al.
    assert (parse("""
            foo :: ([Bool], [Char])
            foo = let f :: (forall a. [a] -> [a]) -> ([Bool], [Char])
                      f x = (x [True, False], x ['a', 'b'])
            in f reverse
            """) == [
        {
            "foo": TypeScheme.from_str("([Bool], [Char])")
        },
        Equation(
            "foo",
            [],
            Let(
                {
                    "f":
                    build_lambda(
                        ["x"],
                        parse_expression("(x [True, False], x ['a', 'b'])"))
                },
                build_application("f", Identifier("reverse")),
                {
                    "f":
                    TypeScheme.from_str(
                        "(forall a. [a] -> [a]) -> ([Bool], [Char])")
                },
            ),
        ),
    ])
Exemple #2
0
def welltyped_applications(args) -> Application:
    # To make this well-typed we simply create:
    #   (\_anonN -> ...  (\_anon2 -> (\_anon1 -> e1) e2) e3...) eN
    #
    anonymous_names = namesupply(prefix="_anon")
    result, *exprs = args
    for expr in exprs:
        result = build_application(build_lambda(next(anonymous_names), result), expr)
    return result
Exemple #3
0
 def _arith_exprs(self, term1, operator, term2):
     return build_application(operator, term1, term2)
Exemple #4
0
 def application(self, tree):
     return build_application(*tree.children)
Exemple #5
0
    def compile(self) -> AST:
        """Return the compiled form of the function definition.

        """
        from xotl.fl.ast.expressions import build_lambda, build_application

        # This is similar to the function `match` in 5.2 of [PeytonJones1987];
        # but I want to avoid *enlarging* simple functions needlessly.
        if self.arity:
            vars = list(namesupply(f".{self.name}_arg", limit=self.arity))
            body: AST = NO_MATCH_ERROR
            for eq in self.equations:
                dfn = eq.body
                patterns: Iterable[Tuple[str,
                                         Pattern]] = zip(vars, eq.patterns)
                for var, pattern in patterns:
                    if isinstance(pattern, str):
                        # Our algorithm is trivial but comes with a cost:
                        # ``id x = x`` is must be translated to
                        # ``id = \.id_arg0 -> (\x -> x) .id_arg0``.
                        dfn = Application(Lambda(pattern, dfn),
                                          Identifier(var))
                    elif isinstance(pattern, Literal):
                        # ``fib 0 = 1``; is transformed to
                        # ``fib = \.fib_arg0 -> <MatchLiteral 0> .fib_arg0 1``
                        dfn = build_application(
                            Identifier(MatchLiteral(pattern)),  # type: ignore
                            Identifier(var),
                            dfn,
                        )
                    elif isinstance(pattern, ConsPattern):
                        if not pattern.params:
                            # This is just a Match; similar to MatchLiteral
                            dfn = build_application(
                                Identifier(Match(
                                    pattern.cons)),  # type: ignore
                                Identifier(var),
                                dfn,
                            )
                        else:
                            for i, param in reversed(
                                    list(enumerate(pattern.params, 1))):
                                if isinstance(param, str):
                                    dfn = build_application(
                                        Identifier(Extract(pattern.cons,
                                                           i)),  # type: ignore
                                        Identifier(var),
                                        Lambda(param, dfn),
                                    )
                                else:
                                    raise NotImplementedError(
                                        f"Nested patterns {param}")
                    else:
                        assert False
                body = build_lambda(
                    vars, build_application(MATCH_OPERATOR, dfn, body))
            return body
        else:
            # This should be a simple value, so we return the body of the
            # first equation.
            return self.equations[0].body  # type: ignore
Exemple #6
0
    Literal, value=st.text(), type_=st.just(StringType)
)
chars: SearchStrategy[Literal] = st.builds(
    Literal, value=st.characters(), type_=st.just(CharType)
)
dates: SearchStrategy[Literal] = st.builds(
    Literal, value=st.dates(), type_=st.just(DateType)
)
datetimes: SearchStrategy[Literal] = st.builds(
    Literal, value=st.datetimes(), type_=st.just(DateTimeType)
)


_apps_args = st.lists(expressions, min_size=2, max_size=100)

maybe_unsafe_applications: SearchStrategy[Application] = _apps_args.map(
    lambda args: build_application(*args)
)


@builds(_apps_args)
def welltyped_applications(args) -> Application:
    # To make this well-typed we simply create:
    #   (\_anonN -> ...  (\_anon2 -> (\_anon1 -> e1) e2) e3...) eN
    #
    anonymous_names = namesupply(prefix="_anon")
    result, *exprs = args
    for expr in exprs:
        result = build_application(build_lambda(next(anonymous_names), result), expr)
    return result