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])") }, ), ), ])
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
def _arith_exprs(self, term1, operator, term2): return build_application(operator, term1, term2)
def application(self, tree): return build_application(*tree.children)
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
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