CSCI: 4500/6500 Programming Languages Back to the Basics: Steps in Inventing a Language Programming an Evaluator Definition

Total Page:16

File Type:pdf, Size:1020Kb

CSCI: 4500/6500 Programming Languages Back to the Basics: Steps in Inventing a Language Programming an Evaluator Definition CSCI: 4500/6500 Programming Languages Functional Programming Languages Part 3: Evaluation and Application Cycle Lazy Evaluation LuisGuillermo.com Maria Hybinette, UGA 1 Maria Hybinette, UGA 2 Back to the Basics: Steps in Inventing a Language ! Design the grammar ! Meta circular evaluaturs » What strings are in the language? ! Evaluate & Apply » Use BNF to describe all the strings in the language ! Lazy and Aggressive Evaluation ! Make up the evaluation rules » Describe what everything the grammar can produce means ! Build an evaluator » A procedure that evaluates expressions in the language – The evaluator: ! determines the meaning of expressions in the programming language, is just another program. Maria Hybinette, UGA 3 Maria Hybinette, UGA 4 Programming an Evaluator Definition: A Metacircular Evaluator ! An evaluator that is written in the same ! If a language is just a program, what language language that it evaluates is said to be should we program the language (evaluator) metacircular Sounds like recursion: It's circular recursion. There is no in? termination condition. It's a chicken-and-the-egg kind of thing. (There's actually a hidden termination condition: the bootstrapping process.) ! One more requirement: The language interpreted does not need additional definitions of semantics other than that is defined for the evaluator (sounds circular). » Example: – The C compiler is written is C but is not meta circular because the compiler specifies extremely detailed and precise semantics for each and every construct that it Maria Hybinette, UGA 5 Maria Hybinette, UGA interprets. 6 Example: Procedural Building Evaluation Basics Blocks Observation: This is recursive ( define (square x) (* x x) )! To evaluate a combination: » ( square (+ 2 5) ) ! 49! ! Evaluate each element (all the ( define (sum-of-squares x y) !; use square for! subexpressions) of the combination (+ (square x) (square y) ) !; x2 + y2! » ( sum-of-squares 3 4) ! 25! ! Apply the procedure to the value of the left- ( define (f a)! most subexpression (the operator) to the ( sum-of-squares (+ a 1) (* a 2)))! arguments that are the values of the other values of the » (f 5) ! 136 ! subexpressions (the operands) 390! operands percolate upward 26! 15! ! square - is a compound procedure which is given the name square which is represents the operation of multiplying something by itself. Evaluation rule is applied on 4 * ! Evaluating the definition creates the compound procedure and associates it combinations:! 24! with the name square (lookup) + 2 + 3 5 7 (* (+ 2 (* 4 6))! ! Application: To apply a compound procedure to arguments, evaluate the body (+ 3 5 7) )! of the procedure with each formal parameter replaced by the ‘real’ arguments. (substitution model -- an assignment model <-variable<-env ) Maria Hybinette, UGA * 4 6 7 Maria Hybinette, UGA 8 Environmental Model of Evaluation Core of the Evaluator 1. To evaluate a combination (compound expression) ! Basic cycle in which • evaluate all the subexpressions and then » expressions to be evaluated in environments are • apply the value of the operator subexpression (first » reduced to procedures to be applied to arguments, expression) to the values of the operand subexpressions ! Which in turn are reduced to new expressions (other expressions). » to be evaluated in new environments, and so on, 2. To apply a procedure to a list of arguments, » until we get down to • evaluate the body of the procedure in a new environment – symbols, whose values are looked up in the environment (by a frame) that binds the formal parameters of the procedure to the arguments to which the procedure is – primitive procedures, which are applied directly. applied to. &'(#% &'(#% procedure, procedure, expression, expression, arguments arguments environment environment !""#$% !""#$% Maria Hybinette, UGA 9 Maria Hybinette, UGA 10 The evaluator - metacircularity ( eval expression environment ) Eval ! Evaluates the the expression relative to the environment (define (eval exp env)! » Examples: environments (returns a specifies for the environment) (cond ((self-evaluating? exp) exp)! – scheme-report-environment version ((variable? exp) (lookup-variable-value exp env))! ((quoted? exp) (text-of-quotation exp))! – null-environment version ((assignment? exp) (eval-assignment exp env))! ! Primitives: ((definition? exp) (eval-definition exp env))! » self-evaluating expressions, such as numbers, eval returns the ((if? exp) (eval-if exp env))! expression itself ((lambda? exp)! (make-procedure (lambda-parameters exp)! » variables, looks up variables in the environment (lambda-body exp)! ! Some special forms (lambda, if, define etc). eval provide direct env))! implementation: ((begin? exp) ! (eval-sequence (begin-actions exp) env))! » Example: quoted: returns expression that was quoted ((cond? exp) (eval (cond->if exp) env))! ! Others lists: ((application? exp)! (apply (eval (operator exp) env)! » eval calls itself recursively on each element and then calls apply, (list-of-values (operands exp) env)))! passing as argument the value of the first element (which must be a (else! function) and a list of the remaining elements. Finally, eval returns what (error "Unknown expression type - EVAL" exp))) apply returned Maria Hybinette, UGA 11 Maria Hybinette, UGA 12 Eval: Example apply (eval ‘( * 7 3 ) (scheme-report-environment 5)) ! ! !=> 21! ! apply applies its first argument (a function) and applies it to its second argument (a list) (eval (cons '* (list 7 3)) (scheme-report-environment 5)) ! ( apply max '(3 7 2 9) ) => 9 ! !=> 21! ! Primitive function, apply invokes the actual function. ! Non-primitive function ( f ), » Retrieves the referencing environment in which the function’s lambda expression was originally evaluated and Current Scheme doesn’t recognize ‘scheme-report-environment ’ adds the names of the function’s parameters (the list) (call this resulting environment (e) ) » Retrieves the list of expressions that make up the body of f. » Passes the body’s expression together with e one at a time to eval. Finally, apply returns what the eval of the last expression in the body of f returned. Maria Hybinette, UGA 13 Maria Hybinette, UGA 14 Apply Example: Evaluating ( cadr p ) (define (apply procedure arguments)! ! ( define cadr ( lambda (x) ( car ( cdr x) ) ) ) (cond ((primitive-procedure? procedure)! ! Stored Internally as three element list C: ( E (x) ( car ( cdr (x) ) ) ) (apply-primitive-procedure procedure arguments))! ((compound-procedure? procedure)! – surrounding referencing environment (global) (eval-sequence! – list of parameters (x) (procedure-body procedure)! – list of body expressions (one element: ( car ( cdr x) ) ) (extend-environment! ! Suppose: p is defined to be a list: ( define p ‘(a b) ) (procedure-parameters procedure)! » (cadr p) => b arguments! (procedure-environment procedure))))! ! Evaluating ( cadr p ) scheme interpreter executes: (else! » ( eval ‘(cadr p) (scheme-report-environment 5) ) (error! – Note: assumes p is defined in scheme-report-environment 5 "Unknown procedure type - APPLY" procedure))))! 1. Evaluate the car of it’s car of the first argument, » cadr via a recursive call returns function c to which cadr is bound, represented internally as a three element list C. 2. Eval calls itself recursively on ‘p’ returning (a, b) 3. Execute (apply c ‘(a b)) and return results Maria Hybinette, UGA 15 Maria Hybinette, UGA 16 &'(#% Example: Evaluating ( cadr p ) Summary of Scheme !""#$% ! ( define cadr ( lambda (x) ( car ( cdr x) ) ) ) ! The core of a Scheme evaluator is eval and ! Suppose: p is defined to be a list: ( define p ‘(a b) ) apply, procedures that are defined in terms ! Evaluating ( cadr p ) scheme interpreter executes: 1. ( eval ‘(cadr p) (scheme-report-environment 5) ) of each other. – Note: assumes p is defined in scheme-report-environment 5 » The eval procedure takes an expression and an 2. Evaluate the car of it’s car of the first argument, environment and evaluates to the value of the » cadr via a recursive call returns function c to which cadr is bound, represented internally as a three element list C. expression in the environment; 3. Eval calls itself recursively on ‘p’ returning (a, b) » The apply procedure takes a procedure and its 4. Execute (apply c ‘(a b)) and return results operands and evaluates to the value of applying the 5. Apply then notice the internal list representation cadr, C. ( E (x) ( car ( cdr (x) ) )) and then apply would execute: procedure to its operands. 6. ( eval ‘(car ( cdr (x))) ( cons (cons ‘x ‘(a b)) E )) and return the results Maria Hybinette, UGA 17 Maria Hybinette, UGA 18 Evaluation Order Example ! Scheme uses applicative order evaluation (as most imperative languages, sometimes called ! (define double (lambda (x) (+ x x))) eager or aggressive evaluation) ! Eager evaluation of ( double (* 3 4) ) ( double 12 ) » Evaluate function arguments before passing them ! to functions ! (+ 12 12) ! 24 Maria Hybinette, UGA 19 Maria Hybinette, UGA 20 Evaluation Order Lazy Evaluation ! Scheme uses applicative order evaluation (as most imperative languages, sometimes called ! Don’t evaluate expressions until their value is eager or aggressive evaluation) really needed. » Evaluate function arguments before passing them » We might save work this way! to functions » We might change the meaning of some ! We can change the evaluator to evaluate expressions, since the order of evaluation matters applications “lazily” instead, by only evaluating the value of an operand when it is needed (also called
Recommended publications
  • Comparative Studies of Programming Languages; Course Lecture Notes
    Comparative Studies of Programming Languages, COMP6411 Lecture Notes, Revision 1.9 Joey Paquet Serguei A. Mokhov (Eds.) August 5, 2010 arXiv:1007.2123v6 [cs.PL] 4 Aug 2010 2 Preface Lecture notes for the Comparative Studies of Programming Languages course, COMP6411, taught at the Department of Computer Science and Software Engineering, Faculty of Engineering and Computer Science, Concordia University, Montreal, QC, Canada. These notes include a compiled book of primarily related articles from the Wikipedia, the Free Encyclopedia [24], as well as Comparative Programming Languages book [7] and other resources, including our own. The original notes were compiled by Dr. Paquet [14] 3 4 Contents 1 Brief History and Genealogy of Programming Languages 7 1.1 Introduction . 7 1.1.1 Subreferences . 7 1.2 History . 7 1.2.1 Pre-computer era . 7 1.2.2 Subreferences . 8 1.2.3 Early computer era . 8 1.2.4 Subreferences . 8 1.2.5 Modern/Structured programming languages . 9 1.3 References . 19 2 Programming Paradigms 21 2.1 Introduction . 21 2.2 History . 21 2.2.1 Low-level: binary, assembly . 21 2.2.2 Procedural programming . 22 2.2.3 Object-oriented programming . 23 2.2.4 Declarative programming . 27 3 Program Evaluation 33 3.1 Program analysis and translation phases . 33 3.1.1 Front end . 33 3.1.2 Back end . 34 3.2 Compilation vs. interpretation . 34 3.2.1 Compilation . 34 3.2.2 Interpretation . 36 3.2.3 Subreferences . 37 3.3 Type System . 38 3.3.1 Type checking . 38 3.4 Memory management .
    [Show full text]
  • (Pdf) of from Push/Enter to Eval/Apply by Program Transformation
    From Push/Enter to Eval/Apply by Program Transformation MaciejPir´og JeremyGibbons Department of Computer Science University of Oxford [email protected] [email protected] Push/enter and eval/apply are two calling conventions used in implementations of functional lan- guages. In this paper, we explore the following observation: when considering functions with mul- tiple arguments, the stack under the push/enter and eval/apply conventions behaves similarly to two particular implementations of the list datatype: the regular cons-list and a form of lists with lazy concatenation respectively. Along the lines of Danvy et al.’s functional correspondence between def- initional interpreters and abstract machines, we use this observation to transform an abstract machine that implements push/enter into an abstract machine that implements eval/apply. We show that our method is flexible enough to transform the push/enter Spineless Tagless G-machine (which is the semantic core of the GHC Haskell compiler) into its eval/apply variant. 1 Introduction There are two standard calling conventions used to efficiently compile curried multi-argument functions in higher-order languages: push/enter (PE) and eval/apply (EA). With the PE convention, the caller pushes the arguments on the stack, and jumps to the function body. It is the responsibility of the function to find its arguments, when they are needed, on the stack. With the EA convention, the caller first evaluates the function to a normal form, from which it can read the number and kinds of arguments the function expects, and then it calls the function body with the right arguments.
    [Show full text]
  • Application and Interpretation
    Programming Languages: Application and Interpretation Shriram Krishnamurthi Brown University Copyright c 2003, Shriram Krishnamurthi This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 United States License. If you create a derivative work, please include the version information below in your attribution. This book is available free-of-cost from the author’s Web site. This version was generated on 2007-04-26. ii Preface The book is the textbook for the programming languages course at Brown University, which is taken pri- marily by third and fourth year undergraduates and beginning graduate (both MS and PhD) students. It seems very accessible to smart second year students too, and indeed those are some of my most successful students. The book has been used at over a dozen other universities as a primary or secondary text. The book’s material is worth one undergraduate course worth of credit. This book is the fruit of a vision for teaching programming languages by integrating the “two cultures” that have evolved in its pedagogy. One culture is based on interpreters, while the other emphasizes a survey of languages. Each approach has significant advantages but also huge drawbacks. The interpreter method writes programs to learn concepts, and has its heart the fundamental belief that by teaching the computer to execute a concept we more thoroughly learn it ourselves. While this reasoning is internally consistent, it fails to recognize that understanding definitions does not imply we understand consequences of those definitions. For instance, the difference between strict and lazy evaluation, or between static and dynamic scope, is only a few lines of interpreter code, but the consequences of these choices is enormous.
    [Show full text]
  • Stepping Ocaml
    Stepping OCaml TsukinoFurukawa YouyouCong KenichiAsai Ochanomizu University Tokyo, Japan {furukawa.tsukino, so.yuyu, asai}@is.ocha.ac.jp Steppers, which display all the reduction steps of a given program, are a novice-friendly tool for un- derstanding program behavior. Unfortunately, steppers are not as popular as they ought to be; indeed, the tool is only available in the pedagogical languages of the DrRacket programming environment. We present a stepper for a practical fragment of OCaml. Similarly to the DrRacket stepper, we keep track of evaluation contexts in order to reconstruct the whole program at each reduction step. The difference is that we support effectful constructs, such as exception handling and printing primitives, allowing the stepper to assist a wider range of users. In this paper, we describe the implementationof the stepper, share the feedback from our students, and show an attempt at assessing the educational impact of our stepper. 1 Introduction Programmers spend a considerable amount of time and effort on debugging. In particular, novice pro- grammers may find this process extremely painful, since existing debuggers are usually not friendly enough to beginners. To use a debugger, we have to first learn what kinds of commands are available, and figure out which would be useful for the current purpose. It would be even harder to use the com- mand in a meaningful manner: for instance, to spot the source of an unexpected behavior, we must be able to find the right places to insert breakpoints, which requires some programming experience. Then, is there any debugging tool that is accessible to first-day programmers? In our view, the algebraic stepper [1] of DrRacket, a pedagogical programming environment for the Racket language, serves as such a tool.
    [Show full text]
  • A Practical Introduction to Python Programming
    A Practical Introduction to Python Programming Brian Heinold Department of Mathematics and Computer Science Mount St. Mary’s University ii ©2012 Brian Heinold Licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported Li- cense Contents I Basics1 1 Getting Started 3 1.1 Installing Python..............................................3 1.2 IDLE......................................................3 1.3 A first program...............................................4 1.4 Typing things in...............................................5 1.5 Getting input.................................................6 1.6 Printing....................................................6 1.7 Variables...................................................7 1.8 Exercises...................................................9 2 For loops 11 2.1 Examples................................................... 11 2.2 The loop variable.............................................. 13 2.3 The range function............................................ 13 2.4 A Trickier Example............................................. 14 2.5 Exercises................................................... 15 3 Numbers 19 3.1 Integers and Decimal Numbers.................................... 19 3.2 Math Operators............................................... 19 3.3 Order of operations............................................ 21 3.4 Random numbers............................................. 21 3.5 Math functions............................................... 21 3.6 Getting
    [Show full text]
  • Making a Faster Curry with Extensional Types
    Making a Faster Curry with Extensional Types Paul Downen Simon Peyton Jones Zachary Sullivan Microsoft Research Zena M. Ariola Cambridge, UK University of Oregon [email protected] Eugene, Oregon, USA [email protected] [email protected] [email protected] Abstract 1 Introduction Curried functions apparently take one argument at a time, Consider these two function definitions: which is slow. So optimizing compilers for higher-order lan- guages invariably have some mechanism for working around f1 = λx: let z = h x x in λy:e y z currying by passing several arguments at once, as many as f = λx:λy: let z = h x x in e y z the function can handle, which is known as its arity. But 2 such mechanisms are often ad-hoc, and do not work at all in higher-order functions. We show how extensional, call- It is highly desirable for an optimizing compiler to η ex- by-name functions have the correct behavior for directly pand f1 into f2. The function f1 takes only a single argu- expressing the arity of curried functions. And these exten- ment before returning a heap-allocated function closure; sional functions can stand side-by-side with functions native then that closure must subsequently be called by passing the to practical programming languages, which do not use call- second argument. In contrast, f2 can take both arguments by-name evaluation. Integrating call-by-name with other at once, without constructing an intermediate closure, and evaluation strategies in the same intermediate language ex- this can make a huge difference to run-time performance in presses the arity of a function in its type and gives a princi- practice [Marlow and Peyton Jones 2004].
    [Show full text]
  • Advanced Tcl E D
    PART II I I . A d v a n c Advanced Tcl e d T c l Part II describes advanced programming techniques that support sophisticated applications. The Tcl interfaces remain simple, so you can quickly construct pow- erful applications. Chapter 10 describes eval, which lets you create Tcl programs on the fly. There are tricks with using eval correctly, and a few rules of thumb to make your life easier. Chapter 11 describes regular expressions. This is the most powerful string processing facility in Tcl. This chapter includes a cookbook of useful regular expressions. Chapter 12 describes the library and package facility used to organize your code into reusable modules. Chapter 13 describes introspection and debugging. Introspection provides information about the state of the Tcl interpreter. Chapter 14 describes namespaces that partition the global scope for vari- ables and procedures. Namespaces help you structure large Tcl applications. Chapter 15 describes the features that support Internationalization, includ- ing Unicode, other character set encodings, and message catalogs. Chapter 16 describes event-driven I/O programming. This lets you run pro- cess pipelines in the background. It is also very useful with network socket pro- gramming, which is the topic of Chapter 17. Chapter 18 describes TclHttpd, a Web server built entirely in Tcl. You can build applications on top of TclHttpd, or integrate the server into existing appli- cations to give them a web interface. TclHttpd also supports regular Web sites. Chapter 19 describes Safe-Tcl and using multiple Tcl interpreters. You can create multiple Tcl interpreters for your application. If an interpreter is safe, then you can grant it restricted functionality.
    [Show full text]
  • CSE341, Fall 2011, Lecture 17 Summary
    CSE341, Fall 2011, Lecture 17 Summary Standard Disclaimer: This lecture summary is not necessarily a complete substitute for attending class, reading the associated code, etc. It is designed to be a useful resource for students who attended class and are later reviewing the material. This lecture covers three topics that are all directly relevant to the upcoming homework assignment in which you will use Racket to write an interpreter for a small programming language: • Racket's structs for defining new (dynamic) types in Racket and contrasting them with manually tagged lists [This material was actually covered in the \Monday section" and only briefly reviewed in the other materials for this lecture.] • How a programming language can be implemented in another programming language, including key stages/concepts like parsing, compilation, interpretation, and variants thereof • How to implement higher-order functions and closures by explicitly managing and storing environments at run-time One-of types with lists and dynamic typing In ML, we studied one-of types (in the form of datatype bindings) almost from the beginning, since they were essential for defining many kinds of data. Racket's dynamic typing makes the issue less central since we can simply use primitives like booleans and cons cells to build anything we want. Building lists and trees out of dynamically typed pairs is particularly straightforward. However, the concept of one-of types is still prevalent. For example, a list is null or a cons cell where there cdr holds a list. Moreover, Racket extends its Scheme predecessor with something very similar to ML's constructors | a special form called struct | and it is instructive to contrast the two language's approaches.
    [Show full text]
  • Specialising Dynamic Techniques for Implementing the Ruby Programming Language
    SPECIALISING DYNAMIC TECHNIQUES FOR IMPLEMENTING THE RUBY PROGRAMMING LANGUAGE A thesis submitted to the University of Manchester for the degree of Doctor of Philosophy in the Faculty of Engineering and Physical Sciences 2015 By Chris Seaton School of Computer Science This published copy of the thesis contains a couple of minor typographical corrections from the version deposited in the University of Manchester Library. [email protected] chrisseaton.com/phd 2 Contents List of Listings7 List of Tables9 List of Figures 11 Abstract 15 Declaration 17 Copyright 19 Acknowledgements 21 1 Introduction 23 1.1 Dynamic Programming Languages.................. 23 1.2 Idiomatic Ruby............................ 25 1.3 Research Questions.......................... 27 1.4 Implementation Work......................... 27 1.5 Contributions............................. 28 1.6 Publications.............................. 29 1.7 Thesis Structure............................ 31 2 Characteristics of Dynamic Languages 35 2.1 Ruby.................................. 35 2.2 Ruby on Rails............................. 36 2.3 Case Study: Idiomatic Ruby..................... 37 2.4 Summary............................... 49 3 3 Implementation of Dynamic Languages 51 3.1 Foundational Techniques....................... 51 3.2 Applied Techniques.......................... 59 3.3 Implementations of Ruby....................... 65 3.4 Parallelism and Concurrency..................... 72 3.5 Summary............................... 73 4 Evaluation Methodology 75 4.1 Evaluation Philosophy
    [Show full text]
  • Language Design and Implementation Using Ruby and the Interpreter Pattern
    Language Design and Implementation using Ruby and the Interpreter Pattern Ariel Ortiz Information Technology Department Tecnológico de Monterrey, Campus Estado de México Atizapán de Zaragoza, Estado de México, Mexico. 52926 [email protected] ABSTRACT to explore different language concepts and programming styles. In this paper, the S-expression Interpreter Framework (SIF) is Section 4 describes briefly how the SIF has been used in class. presented as a tool for teaching language design and The conclusions are found in section 5. implementation. The SIF is based on the interpreter design pattern and is written in the Ruby programming language. Its core is quite 1.1 S-Expressions S-expressions (symbolic expressions) are a parenthesized prefix small, but it can be easily extended by adding primitive notation, mainly used in the Lisp family languages. They were procedures and special forms. The SIF can be used to demonstrate selected as the framework’s source language notation because advanced language concepts (variable scopes, continuations, etc.) they offer important advantages: as well as different programming styles (functional, imperative, and object oriented). • Both code and data can be easily represented. Adding a new language construct is pretty straightforward. • Categories and Subject Descriptors The number of program elements is minimal, thus a parser is − relatively easy to write. D.3.4 [Programming Languages]: Processors interpreters, • run-time environments. The arity of operators doesn’t need to be fixed, so, for example, the + operator can be defined to accept any number of arguments. General Terms • There are no problems regarding operator precedence or Design, Languages. associativity, because every operator has its own pair of parentheses.
    [Show full text]
  • Functional Programming Lecture 1: Introduction
    Functional Programming Lecture 4: Closures and lazy evaluation Viliam Lisý Artificial Intelligence Center Department of Computer Science FEE, Czech Technical University in Prague [email protected] Last lecture • Functions with variable number of arguments • Higher order functions – map, foldr, foldl, filter, compose Binding scopes A portion of the source code where a value is bound to a given name • Lexical scope – functions use bindings available where defined • Dynamic scope – functions use bindings available where executed Ben Wood's slides Eval Eval is a function defined in the top level context (define x 5) (define (f y) (eval '(+ x y))) Fails because of lexical scoping Otherwise the following would be problematic (define (eval x) (eval-expanded (macro-expand x))) Eval in R5RS (eval expression environment) Where the environment is one of (interaction-environment) (global defines) (scheme-report-environment x) (before defines) (null-environment x) (only special forms) None of them allows seeing local bindings Cons (define (my-cons x y) (lambda (m) (m x y))) (define (my-car p) (p (lambda (x y) x))) (define (my-cdr s) (p (lambda (x y) y))) Currying Transforms function to allow partial application not curried 푓: 퐴 × 퐵 → 퐶 curried 푓: 퐴 → (퐵 → 퐶) not curried 푓: 퐴 × 퐵 × 퐶 → 퐷 curried 푓: 퐴 → (퐵 → 퐶 → 퐷 ) Picture: Haskell Curry from Wikipedia Currying (define (my-curry1 f) (lambda args (lambda rest (apply f (append args rest))))) (define (my-curry f) (define (c-wrap f stored-args) (lambda args (let ((all (append stored-args args)))
    [Show full text]
  • Records in Haskell
    Push/enter vs eval/apply Simon Marlow Simon Peyton Jones The question Consider the call (f x y). We can either Evaluate f, and then apply it to its arguments, or Push x and y, and enter f Both admit fully-general tail calls Which is better? Push/enter for (f x y) Stack of "pending arguments" Push y, x onto stack, enter (jump to) f f knows its own arity (say 1). It checks there is at least one argument on the stack. Grabs that argument, and executes its body, then enters its result (presumably a function) which consumes y Eval/apply for (f x y) Caller evaluates f, inspects result, which must be a function. Extracts arity from the function value. (Say it is 1.) Calls fn passing one arg (exactly what it is expecting) Inspects result, which must be a function. Extracts its arity... etc Known functions Often f is a known function let f x y = ... in ...(f 3 5).... In this case, we know f's arity statically; just load the arguments into registers and call f. This "known function" optimisation applies whether we are using push/enter or eval/apply So we only consider unknown calls from now on. Uncurried functions If f is an uncurried function: f :: (Int,Int) -> Int ....f (3,4)... Then a call site must supply exactly the right number of args So matching args expected by function with args supplied by call site is easier (=1). But we want efficient curried functions too And, in a lazy setting, can't do an efficient n- arg call for an unknown function, because it might not be strict.
    [Show full text]