130 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Factor
		
	
	
		
		
			
		
	
	
			130 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Factor
		
	
	
| 
								 | 
							
								#! A lambda expression manipulator, by Matthew Willis
							 | 
						||
| 
								 | 
							
								USING: lazy-lists strings arrays hashtables 
							 | 
						||
| 
								 | 
							
								sequences namespaces words parser kernel ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IN: lambda
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SYMBOL: lambda-names
							 | 
						||
| 
								 | 
							
								TUPLE: lambda-node self expr name ;
							 | 
						||
| 
								 | 
							
								TUPLE: apply-node func arg ;
							 | 
						||
| 
								 | 
							
								TUPLE: var-node name ; #! var is either a var, name, or pointer to a lambda-node
							 | 
						||
| 
								 | 
							
								TUPLE: beta-node expr lambdas ; #! a namespace node
							 | 
						||
| 
								 | 
							
								TUPLE: alien-node word ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: lambda-node equal? 2drop f ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								GENERIC: bind-var
							 | 
						||
| 
								 | 
							
								M: lambda-node bind-var ( binding lambda -- ) 
							 | 
						||
| 
								 | 
							
								    lambda-node-expr bind-var ; 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: apply-node bind-var ( binding apply -- )
							 | 
						||
| 
								 | 
							
								    [ apply-node-func bind-var ] 2keep apply-node-arg bind-var ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: var-node bind-var ( binding var-node -- )
							 | 
						||
| 
								 | 
							
								    2dup var-node-name swap lambda-node-name = 
							 | 
						||
| 
								 | 
							
								    [ set-var-node-name ] [ 2drop ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: alien-node bind-var ( binding alien -- ) 2drop ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								C: lambda-node ( expr var lambda -- lambda )
							 | 
						||
| 
								 | 
							
								    swapd [ set-lambda-node-name ] keep
							 | 
						||
| 
								 | 
							
								    [ set-lambda-node-expr ] 2keep
							 | 
						||
| 
								 | 
							
								    dup [ set-lambda-node-self ] keep
							 | 
						||
| 
								 | 
							
								    [ swap bind-var ] keep ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								GENERIC: beta-push
							 | 
						||
| 
								 | 
							
								#! push the beta further down the syntax tree
							 | 
						||
| 
								 | 
							
								#!  this is how lambda achieves lazy beta reduction and efficient cloning.
							 | 
						||
| 
								 | 
							
								#!  everything outside of the beta must have been cloned.
							 | 
						||
| 
								 | 
							
								M: lambda-node beta-push ( beta lambda -- lambda )
							 | 
						||
| 
								 | 
							
								    clone dup lambda-node-expr pick set-beta-node-expr
							 | 
						||
| 
								 | 
							
								    [ set-lambda-node-expr ] keep ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: apply-node beta-push ( beta apply -- apply )
							 | 
						||
| 
								 | 
							
								    #! push the beta into each branch, cloning the beta
							 | 
						||
| 
								 | 
							
								    swap dup clone 
							 | 
						||
| 
								 | 
							
								    pick apply-node-func swap [ set-beta-node-expr ] keep swap
							 | 
						||
| 
								 | 
							
								    rot apply-node-arg swap [ set-beta-node-expr ] keep
							 | 
						||
| 
								 | 
							
								    <apply-node> ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: var-node beta-push ( beta var -- expr )
							 | 
						||
| 
								 | 
							
								    #! substitute the variable with the appropriate entry from the
							 | 
						||
| 
								 | 
							
								    #! beta namespace
							 | 
						||
| 
								 | 
							
								    tuck var-node-name swap beta-node-lambdas hash dup
							 | 
						||
| 
								 | 
							
								    [ nip ] [ drop ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: beta-node beta-push ( beta inner-beta -- beta )
							 | 
						||
| 
								 | 
							
								    #! combines the namespaces of two betas
							 | 
						||
| 
								 | 
							
								    dup beta-node-lambdas rot beta-node-lambdas hash-union
							 | 
						||
| 
								 | 
							
								    swap [ set-beta-node-lambdas ] keep ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: alien-node beta-push ( beta alien -- alien ) nip ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: beta-reduce ( apply -- beta )
							 | 
						||
| 
								 | 
							
								    #! construct a beta-node which carries the namespace of the lambda
							 | 
						||
| 
								 | 
							
								    dup apply-node-arg swap apply-node-func dup lambda-node-expr -rot
							 | 
						||
| 
								 | 
							
								    lambda-node-self H{ } clone [ set-hash ] keep <beta-node> ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DEFER: evaluate
							 | 
						||
| 
								 | 
							
								: left-reduce ( apply -- apply/f )
							 | 
						||
| 
								 | 
							
								    #! we are at an application node -- evaluate the function
							 | 
						||
| 
								 | 
							
								    dup apply-node-func evaluate dup
							 | 
						||
| 
								 | 
							
								    [ swap [ set-apply-node-func ] keep ]
							 | 
						||
| 
								 | 
							
								    [ nip ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: alien-reduce ( apply -- node/f )
							 | 
						||
| 
								 | 
							
								    #! we have come to an alien application, which requires us to
							 | 
						||
| 
								 | 
							
								    #! fully normalize the argument before proceeding
							 | 
						||
| 
								 | 
							
								    dup apply-node-arg evaluate dup
							 | 
						||
| 
								 | 
							
								    [ swap [ set-apply-node-arg ] keep ]
							 | 
						||
| 
								 | 
							
								    [ #! right side is normalized, we are ready to do the alien application
							 | 
						||
| 
								 | 
							
								        drop dup apply-node-arg swap apply-node-func
							 | 
						||
| 
								 | 
							
								        alien-node-word "lambda" lookup execute
							 | 
						||
| 
								 | 
							
								    ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								GENERIC: evaluate
							 | 
						||
| 
								 | 
							
								#! There are 
							 | 
						||
| 
								 | 
							
								#!   beta-reduction, beta-pushing, and name replacing.
							 | 
						||
| 
								 | 
							
								: normalize ( expr -- expr )
							 | 
						||
| 
								 | 
							
								    dup evaluate [ nip normalize ] when* ;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								M: lambda-node evaluate ( lambda -- node/f ) drop f ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: apply-node evaluate ( apply -- node )
							 | 
						||
| 
								 | 
							
								    dup apply-node-func lambda-node?
							 | 
						||
| 
								 | 
							
								    [ beta-reduce ] 
							 | 
						||
| 
								 | 
							
								    [ 
							 | 
						||
| 
								 | 
							
								        dup apply-node-func alien-node?
							 | 
						||
| 
								 | 
							
								        [ alien-reduce ]
							 | 
						||
| 
								 | 
							
								        [ left-reduce ] if
							 | 
						||
| 
								 | 
							
								    ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: var-node evaluate ( var -- node/f ) 
							 | 
						||
| 
								 | 
							
								    var-node-name lambda-names get hash ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: beta-node evaluate ( beta -- node/f ) 
							 | 
						||
| 
								 | 
							
								    dup beta-node-expr beta-push ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: alien-node evaluate ( alien -- node/f ) drop f ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								GENERIC: expr>string
							 | 
						||
| 
								 | 
							
								M: lambda-node expr>string ( lambda-node -- string )
							 | 
						||
| 
								 | 
							
								    [ 
							 | 
						||
| 
								 | 
							
								        dup "(" , lambda-node-name , ". " , 
							 | 
						||
| 
								 | 
							
								        lambda-node-expr expr>string , ")" , 
							 | 
						||
| 
								 | 
							
								    ] { } make concat ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: apply-node expr>string ( apply-node -- string ) 
							 | 
						||
| 
								 | 
							
								    [ 
							 | 
						||
| 
								 | 
							
								        dup "(" , apply-node-func expr>string , " " , 
							 | 
						||
| 
								 | 
							
								        apply-node-arg expr>string , ")" , 
							 | 
						||
| 
								 | 
							
								    ] { } make concat ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: var-node expr>string ( variable-node -- string ) 
							 | 
						||
| 
								 | 
							
								    var-node-name dup string? [ lambda-node-name ] unless ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: alien-node expr>string ( alien-node -- string )
							 | 
						||
| 
								 | 
							
								    [ "[" , alien-node-word , "]" , ] { } make concat ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: beta-node expr>string ( beta -- string )
							 | 
						||
| 
								 | 
							
								    [ "beta<" , beta-node-expr expr>string , ">" , ] { } make concat ;
							 |