arXiv:2108.07389v2 [cs.PL] 22 Aug 2021 edmntaeacnrt mlmnaino hssse nt in system this of implementation concrete a demonstrate We 01AscainfrCmuigMachinery. Computing for Association 2021 © a rtietfidwt h eeomn fLs nte17sa 1970s the in Lisp of development the with identified first was C utb ooe.Asrcigwt rdti emte.T permitted. is credit with Abstracting honored. be must ACM h uagpolmrfr otedffiut soitdwt co with associated difficulty the to refers problem funarg The Format: Reference ACM C SN978-1-4503-XXXX-X/18/06...$15.00 ISBN ACM iomn skona h uagpolm h uagproblem funarg The problem. funarg the as stack-ba known a is in vironment closures storing with associated difficulty The uie ucinlratv rgamn agae hc i which language, programming reactive functional Juniper nteha.Teeaetovrat fti rbe:uwrsa upwards problem: this of variants two are allocate There availab to heap. is not the solution on are standard The which scope. scope lexical de own lexical it’s identifiers function’s to nest parent refers the of function in bodies nested the the in where arises functions problem The fo environments. languages based programming in functions first-class of lation embedde functional, memory, heap, stack, closure, funarg, KEYWORDS • CONCEPTS CCS disc formally literature. been the haven’t in but problem funarg the solve l that programming other devices in Arduino present solutions limited other discuss resource also extremely on run to signed stack-alloca be to closures allows pren that the F to System extension simple of a fragment present We me cause fragmentation. may ory allocation heap where resources hav memory often limited systems embedded the However, as memory. systems of computing abundance most an for problem stac a be not o can is heap, This closures the cated. when on determine to closures analysis allocate static solut to apply modern is languages The most then. by since taken attention much received hasn’t INTRODUCTION 1 https://doi.org/10.1145/1122445.112245 Online. pages. 5 2021, USA, 01–03, NY, September with Languages, Problem Functional Funarg of the Solving 2021. In Types. Aksoy. Static Fırat and Helbling Caleb subroutines https://doi.org/10.1145/1122445.1122456 F 2,Spebr0–3 01 Online 2021, 01–03, September [email protected] ’21, from IFL permissions requ Request lists, fee. to a redistribute to and/or or servers on post to work publish, this of components n for this Copyrights bear page. copies first that the and on thi tion advantage of commercial ar part copies or that or profit provided all for fee of without granted copies is hard use or classroom digital make to Permission ABSTRACT otaeadisengineering its and Software ; F 2:AMSmoimo mlmnainadApplication and Implementation on Symposium ACM ’21: IFL ucinllanguages Functional etLfyte nin,USA Indiana, Lafayette, West ovn h uagPolmwt ttcTypes Static with Problem Funarg the Solving [email protected] udeUniversity Purdue ae Helbling Caleb → . rcdrs ucin and functions Procedures, rspirseicpermission specific prior ires o aeo distributed or made not e g. oyohrie rre- or otherwise, copy o okfrproa or personal for work s tc n h ulcita- full the and otice we yohr than others by owned C,NwYork, New ACM, 6 closures anguages d stack- r e en- sed allo- k ussed fined de- s ein le We . mpi- eis re to r ted. ion nd nd he m- ed ex e edsrb h olwn contributions: following the describe We ems epi idta,a ona h ucinrtrs any returns, function the as soon as that, mind in keep must We lo rgamn agae al tepst ov h fun the solve to attempts Early language. programming Algol ese osletefnr rbe ahrta nlzn clo analyzing than rather problem funarg the solve to seek we exis since problem, funarg the solving to helpful not is This ad uagpolmrfr otemngmn ftesakwh stack the of management the to refers problem funarg wards n yai cpn,lc fsai ye n ual variab mutable and types static of inc lack factors, scoping, of dynamic number a ing by hampered be for to problem appear [10] the problem analyzed further [9] Moses in tree. must and a structure of data consist based stack a have cannot in calculus closures function that showed and calculus, lambda using . Contributions 1.1 perspective. environmental theoretic type purely a from alloc sens the be in must unique is and contribution values our Therefore boxed heap. the as on treated typically existen are an tials by determined is closures type treat to whose prefer environments, papers plicit These 6–8]. [1, exercise new a oetal aeannepycoue,weestedown the whereas closure), (t non-empty function a another have returns function potentially manage- a may the when stack to the refers of problem ment funarg upwards The downwards. o ecpe ontesakwtotcuigsakcorruptio stack causing without stack itsel the closure down the copied behavior, this be to not Due dynamic. the closure making the variables, deallocati local with capture stack arises may function issue program’s returning an the problem, lex of funarg closure’s top upwards the the the copying to variables) by (captured solved scope easily is problem downwar funarg The problem. funarg downwards the than difficult more a have also may (that closure). function empty another to passed is function a e)adcmoe(pad n onad uagpolm to naturally. problem) and concisely funarg very downwards written and be (upwards compose pr funarg and lan- (downwards map lem) our as T such make functions scopes. can order lexical higher we their lows type, and closures record st over structural polymorphic lexic other a closure’s guage any as a of were viewed type it be the if can Since data. as of function, piece sized calling cally the proble into funarg upwards copied the be from c closure at the size allows closure’s This a time. determining upward statically the by solve problem we narg approach, our ha In problem) solved. funarg adequately upwards been the particular, (in problem narg oa aibe ilb otwe hyaeppe fftestack the off popped are they when lost be will variables local ept h ilso hs al aes ecnedta the that contend we papers, early these of titles the Despite closur function of analysis an made [12] Weizenbaum 1968, In ovn h pad uagpolmi osdrdt emuch be to considered is problem funarg upwards the Solving nlzn lsrsfo yetertcprpciei not is perspective theoretic type a from closures Analyzing • eetne oeal tc loae closures. allocated can stack F enable System to extended of be fragment prenex the how demonstrate We fi[email protected] sablUniversity Istanbul sabl Turkey Istanbul, ıa Aksoy Fırat lscope al ompile lambda ieof size i al- his that e sex- as can- f n A on. les. sures not s For . to m non- ated . fu- s fact lud- ten- ical tial. arg the hat ati- ob- fu- en es n. ds a - IFL ’21, September 01–03, 2021, Online Helbling and Aksoy
environment along with the lambda’s argument for further evalu- Expressions ation. Figure 1 presents the big-step semantics for our language. 4 := G | _G : .4 | 41 42 | ΛU.4 | 4 = Δ( ) Type Schemes E G Δ [EVAL-VAR] f := |∀0.f ⊢ G ⇓ E
Types , , := U | − → | X Δ ⊢ _G : .4 ⇓ (_G.4)[{~ 7→ Δ(~) | ~ ∈ fv(_G : .4)}] [EVAL-ABS] Lexical Scope Types X := {G : , ..., G= : = } 0 0 ′ ′ Δ1 ⊢ 41 ⇓ (_G.43)[Δ2] Δ1 ⊢ 42 ⇓ E Δ2, G 7→ E ⊢ 43 ⇓ E Values Δ1 ⊢ 41 42 ⇓ E E := (_G.4)[Δ] | Λ.4 [EVAL-APP]
Contexts Γ ::= ∅ | Γ,U | Γ, G : [EVAL-TABS] Δ ⊢ ΛU.4 ⇓ Λ.4 Environments Δ := {G 7→ E , ..., G= 7→ E= } Δ ⊢ 41 ⇓ Λ.42 Δ ⊢ 42 ⇓ E 0 0 [EVAL-TAPP] Δ ⊢ 41 ⇓ E Table 1: Grammar Figure 1: Big step semantics
• We discuss a concrete implementation of this approach in 2.2 Typing the Juniper programming language. Figure 2 presents the typing rules for our language. There are sev- • We analyze the limitations of the extension and identify the eral changes made to the type rules for the prenex fragment of Sys- connection between types and closures. tem F. Of primary interest is the T-ABS rule which also constructs • We make an analysis of other approaches found in exist- the type of the lexical scope. The construction of the lexical scope ing programming languages, but haven’t been discussed for- itself is performed by T-DELTA, which finds all free variables within mally in the literature. the lambda, looks up their type in Γ and returns the corresponding lexical scope type. The rule T-TABS is also changed to restrict type 2 EXTENDING SYSTEM F abstractions to contain no free variables themselves which simpli- In this section, we restrict and extend System F to enable stack allo- fies the type system and assists in compilation to a stack based cated closures. We restrict System F to it’s prenex fragment which environment. separates regular System F types into type schemes and types. This is a necessary restriction to prevent the emergence of existential 2.3 Examples types in the type system which prevents determining the sizes of In this section, we will look at two examples that demonstrate that types at compile-time. The primary addition is that of the closure our solution for the funarg problem works for accurately typing types, which are defined as function types with their lexical scopes two of the most commonly used functions in functional program- attached to them. The lexical scopes X are either type variables ming: map and compose. For the map example, we will assume or records of captured variables and their respective types. These that the type system is enriched with a list type constructor. The lexical scope types are are considered equivalent if both the field type of these functions are considerably more noisy than the stan- names and the types of those fields are identical. These additions dard System F types. Fortunately, most of the noise can be elided make it possible for closures to be polymorphic and enable stack through type inference. allocation of the closure since the size of the closure is known stati- cally at compile-time. Table 1 defines the grammar of our language. <0? : ∀U.∀V.∀X.(U−X → V)−{} → U list−{5 : U−X → V}→ V list 2.1 Big-step semantics For the compose example we give the definition of compose as Stack allocation of closures require the lambda values and their lex- well as its type in our System F extension. ical scopes to be propagated and used in pairs. For this reason, we combine the lambda values with their environments into a single 2>B4 := ΛU.ΛV.ΛW.ΛX1 .ΛX2. value representation. When a lambda is applied, a flat representa- tion of the lambda’s lexical scope is constructed and used as the _5 : (V − X1 → W)._6 : (U − X2 → V)._G : U.5 (6 G) Solving the Funarg Problem with Static Types IFL ’21, September 01–03, 2021, Online
G : ∈ Γ [T-VAR] Γ ⊢ G : true : ∀U.∀V.U −{}→ V −{C : U}→ U (4)
Γ, G : ⊢ 4 : Γ ⊢ _G : .4 X false := ΛU.ΛV._C : U._5 : V.5 (5) [T-ABS] Γ ⊢ _G : .4 : − X → false : ∀U.∀V.U −{}→ V −{}→ V (6) Γ ⊢ 41 : − X → Γ ⊢ 42 : [T-APP] Applying the cond operator with true and false in equations Γ ⊢ 41 42 : 7 and 8 reveals why Church-encoding does not suffer from the branching problem. In System F, the branch chosen by cond is Γ,U ⊢ 4 : f fv(4) = ∅ already present in the type system by selecting the type for W. Fun- [T-TABS] Γ ⊢ ΛU.4 : ∀U.f damentally, this occurs because true and false have different type signatures, that also determine the branch taken. Γ ⊢ 4 : ∀U.f [T-TAPP] ((condUVU {C : 0}) C 5 (true U V )) : U (7) Γ ⊢ 4 : f[U := ]
((condU V V {}) C 5 (false U V )) : V (8) ~8 ∈ fv(_G : .4) Γ ⊢ ~0 : 0, ..., Γ ⊢ ~= : = [T-DELTA] However, in a language with sum types and pattern matching Γ ⊢ _G : .4 {~0 : 0, ..., ~= : =} (as Boolean types are in most languages), the branching problem with closures will be present. Whether or not this is a major is- Figure 2: Typing rules. sue is debatable, however, we can say for certain that this removes some generality from our approach. An interesting approach to recovering this generality is a paper on open closures by Scherer and Hoffmann [11], however their approach only applies to simply typed lambda calculus and not for System F. 2>B4 : ∀U.∀V.∀W.∀X .∀X . 1 2 The second limitation appears under the presence of mutually (V − X1 → W)−{}→(U − X2 → V)−{5 : V − X1 → W}→ U recursive functions. When compiling top level functions, we can −{5 : V − X1 → W,6 : U − X2 → V}→ W consider their closure to be empty since we can refer to them us- ing a simple function pointer. For inner functions that are often 3 LIMITATIONS AND EXTENSIONS mutually recursive, the situation is more complicated. The lexical The most obvious limitation of the extension presented in this pa- scope of all functions declared in a let-rec blockcan be constructed per is that all branches in a program that return a closure must have by taking the union of all of the lexical scopes of all the functions the exact same lexical scope. One would think that this would be a declared in the block. This constructs a common lexical scope that problem since in most languages, branches of conditionals may re- can be passed to all the related functions. Therefore, all functions turn lambdas with different lexical scopes, as long as the types are declared in the let-rec block will have identical lexical scope types. equivalent. A close analysis of the cond function in System F when When one function in the let-rec block calls another function combined with Church-encoded Boolean values true and false re- in the same let-rec block, it simply passes the lexical scope that it veals a surprising result, this problem simply does not appear in was passed. Within the lexical scope type itself, we place all the the extension described in this paper. functions within the let-rec block with the non-closure function To further elucidate our point, we define cond operator as a type → . This indicates that this function should be passed the function which takes in a true branch and a false branch and a lexical scope that this function is contained within. Church-encoded Boolean value (as described in equations 3, 4, 5, Extending the system presented in this paper to the impredica- and 6) and returns the respective branch in relation to it’s Boolean tive System F at first glance seems feasible. We believe that the input. funarg problem is orthogonal issue to that of first-class polymor- phism and stack allocated existential types. However we have yet to make a full analysis of how the lexical environments presented cond := ΛU.ΛV.ΛW.ΛX here interact with System F. One possible issue that may crop up _C : U._5 : V._2 : (U −{}→ V − X → W).2 C 5 (1) is subtle interactions with existential types, which can be encoded in System F [2].
4 IMPLEMENTATION cond : ∀U.∀V.∀W.∀X. We have implemented the closure system given here in Juniper U −{} → V −{C : U}→(U −{} → V −X → W)−{C : U, 5 : V}→ W [3], a functional reactive programming language for the Arduino. (2) The Juniper language transpiles all of its code to C++. The analy- sis of C++ in section 5 reveals the issues facing the use of lambdas true := ΛU.ΛV._C : U._5 : V.C (3) as a transpile target. To work around the issues presented in that IFL ’21, September 01–03, 2021, Online Helbling and Aksoy
section, we implement our own function class. This class is con- 5 EXISTING APPROACHES structed by passing in a lexical scope, along with a function pointer. In this section we will analyze a number of different existing lan- In C++, lambda types that do not capture anything can be casted guages and how they solve the funarg problem. To our knowledge to type safe function pointers. We provide our own stack allocated the system presented in this paper is the only language that will closure support by passing in the lexical scope as the first argu- allow the type of a closure to be fully written out with text (ie, it ment to the underlying lambda function. Within this lambda, the does not generate an implicit type or class). compiler inserts variable assignments which extracts the contents In C++, each declaration of a lambda implicitly declares a new of the lexical scope into local variables. Lambdas that do not cap- class [4] and therefore type in the system. Since these classes are ture anything are not passed a lexical scope. auto-generated, it is impossible to write their types using text, and programmers must rely on the auto keyword. These C++ lambdas 1 template