af Yin Wang 11 år siden
25463
Mere som dette
... and use it to change the PATH variable
append-path /home/ywang/bin append-path /usr/local/jdk1.6.0_38/bin append-path /usr/local/eclipse append-path /usr/local/racket/bin
define a function
append-path () { PATH=$PATH:$1 }
Rule 2: Use functions whenever possible
Rule 1: Try NEVER use aliases
Try this
-bash: /etc/profile: line 3: syntax error near unexpected token `then' -bash: /etc/profile: line 3: `if [ -x /usr/libexec/path_helper ]; then'
... and then reload /etc/profile
source /etc/profile
Try this: alias if='crap'
They bring TROUBLE!
But some clever tricks exist when you really need to use it in a neat way
register targetting
tail-call optimization
Yin Wang
"The essence of tail-call optimization is an eta-reduction."
Guy Steele
"It is not procedure call that pushes stack. It is argument evaluation that pushes stack"
closure optimization
procedural integration
maybe used to generate machine code also?
(add 1 2)
inline 'add' instruction
(+ 1 2)
union types
list is a union type
cons
'()
Carl Hewitt
"all good logicians will eventually go crazy"
crazier a few months ago... recovered?
now crazy guy
horrendous typesetting
putting trademark (TM) signs in his papers and concepts that he "invented"
inventor of the "actor model"
Scheme was influenced by actor model
MIT professor
Racket
larceny
Ikarus
clang -O3
gcc -O3
was not happy at UNC
unit tests should be able to be folded up in the editor so that they don't show up when the programmer doesn't want to see them
unit tests can be inserted directly into the code
specifications should be inserted at actual code points
tests are separated from code
The Rock (1996)
Escape from Alcatraz (1979)
Frank Morris
Dummy head found in Morris' cell
The guy must be at least 10x smarter than what is shown in the movie to escape.
I don't believe anybody can get electric saws to cut the bars in a prison!
I don't believe that Morris can take the metal wedge past the metal detector that way. In comparison, the airport security will ask you to go back and go through the metal detector again if the metal detector alarms, until it stops to alarm.
The security at Alcatraz is fatally flawed in today's standards if the movie were true story.
Starring: Clint Eastwood
The best way
(lambda (i:Int) (begin (println "hello world") (* i 2)))
scala> i: Int => { println("hello world") i * 2 }
There is a reason
It will cause confusion and ambiguity when lambdas are used in other pieces of code
Unfortunately Scala didn't choose this syntax for lambda
scala> { i: Int => println("hello world") i * 2 }
But now it has some additional meaning for the first line 'i:Int =>'
This is not consistent with the meaning of {...}
{...} should mean a "block"
This is ugly
But Scala chose the wrong direction
being able to write 'f' as the function value is consistent with the syntax of values
forcing call to be 'f()' is consistent with the syntax of calls
if we can write 'f' as a call
we must write 'f _' to get teh function itelf
if we must write f() as a call
we can treat 'f' as the function itself
seems to be "good idea"
in fact is bad
functional languages usually put the stack on the same memory segment as heap and not to use the processor's push/pop instructions or calling conventions
Thus they are not subject to this restriction
This is also why your prof for first programming class tell you how to convert recursion to loops
most processors are targetting C/C++'s calling conventions
C/C++ also corrupted processor design
because of this C/C++ shit
some code must maintain their own "stack" on the heap
You can never do as well as the compiler
This is like manually compile/CPS code
C/C++ has fixed-size stack
will stack overflow easily
Some codes are naturally recursive
can recurse into arbitrary depth
The best way is: DO NOT USE it
English blog article on how to deal with it
The use of 'const' in the blog is easy to say but hard to do
how much performance gain is there?
too much trouble
not everyone abide by it
ESSENCE
... distributed onto ALL C++ programmers in the whole world
It's a manual interprocedual analysis about "purity" of code
It's easier said than done
just PLEASE DO NOT RETURN CONST!!
ignore my first "rule"
(define: (sum2 (l : List-2-Ints) : Integer) (+ (car l) (car (cdr l))))
Not sure this is good idea
ditto my var-arg argument
only works for this special case (lists)
"can use car and cdr without checks"
(define-type List-2-Ints (List Integer Integer))
pass lists instead
Should not have variable arity functions
parts that may be improved
(: list-length (All (A) ((Listof A) -> Integer))) (define (list-length l) (if (null? l) 0 (add1 (list-length (cdr l)))))
Looks better than ML
may cause unnecessary complexity
may be equivalent to interprocedural analysis in the end
as it contains more control-flow, type checking becomes expensive
contains parts of the case-lambda itself
(case-lambda: [() 0] [([x : Number]) x])
(case-lambda (-> Number) (Number -> Number))
Is unification-based type inference still usedful sometimes?
has only forward type inference
(ann (+ 7 1) Number)
"application of ann onto the value of (+ 7 1) and the variable Number"
This is not only ugly. This is ambiguous!
(let ([#{x : Number} 7]) (add1 x))
I have no intention of letting the users define binding forms
(define: x : Number 7) (define: (id [z : Number]) : Number z)
or just infer the type from 7
a better way may be (define: (x : Number) 7)
Not enough clue about which is type which is value
> Dropbox/prog/Y/racket-test.rkt:25:18: Type Checker: No function domains matched in function application: Types: Zero -> One One -> Positive-Byte Byte -> Positive-Index Index -> Positive-Fixnum Negative-Fixnum -> Nonpositive-Fixnum Nonpositive-Fixnum -> Fixnum Nonnegative-Integer -> Positive-Integer Negative-Integer -> Nonpositive-Integer Integer -> Integer Nonnegative-Exact-Rational -> Positive-Exact-Rational Exact-Rational -> Exact-Rational Nonnegative-Flonum -> Positive-Flonum Flonum -> Flonum Nonnegative-Single-Flonum -> Positive-Single-Flonum Single-Flonum -> Single-Flonum Nonnegative-Inexact-Real -> Positive-Inexact-Real Inexact-Real -> Inexact-Real Nonnegative-Real -> Positive-Real Real -> Real Float-Complex -> Float-Complex Single-Flonum-Complex -> Single-Flonum-Complex Inexact-Complex -> Inexact-Complex Number -> Number Arguments: node Expected result: Tree in: (add1 t)
(: tree-sum (Tree -> Number)) (define tree-sum (lambda (t) (cond [(leaf? t) (leaf-val t)] [(node? t) (+ (tree-sum (add1 t)) (tree-sum (node-right t)))])))
> Dropbox/prog/Y/racket-test.rkt:21:3: Type Checker: Expected Number, but got Void in: (cond ((boolean? t) (leaf-val t)) ((node? t) (+ (tree-sum (node-left t)) (tree-sum (node-right t))))) context...: /Applications/Racket/collects/typed-racket/typecheck/tc-toplevel.rkt:295:0: type-check success /Applications/Racket/collects/typed-racket/typed-racket.rkt:40:4 /Applications/Racket/collects/racket/private/misc.rkt:87:7
(: tree-sum (Tree -> Number)) (define tree-sum (lambda (t) (cond [(boolean? t) (leaf-val t)] [(node? t) (+ (tree-sum (node-left t)) (tree-sum (node-right t)))])))
passes the type checker
(: tree-sum (Tree -> Number)) (define tree-sum (lambda (t) (cond [(boolean? t) 1] [(leaf? t) (leaf-val t)] [(node? t) (+ (tree-sum (node-left t)) (tree-sum (node-right t)))])))
Should Tree? be defined after the union type?
(define-type Tree (U leaf node)) (struct: leaf ([val : Number])) (struct: node ([left : Tree] [right : Tree]))
Can be implemented in a more efficient way than nested if's
case = switch in C
but it is more general than if
It can be expressed by nested if's
definitely needs something like that in the "small" language
much simpler than R6RS
Is there really a need for a "tail call" instruction?
provides a "pinning" mechanism so that developers can declare a block of code within which the CLR is not allowed to move certain pointers
Closures and generators are implemented at a language level and are simply represented as classes on the CLR level.
In the JVM, every unique operation (add two int values, add two float values, etc) has its own unique instruction.
Since the CLR knows about parametric types, it has no problem handling methods overloaded on generic type specializations.
See William Clinger's video
otherwise a conditional needs to be generated for union types
Can use type inference to statically resolve types if possible
List
They will never get close to the "right thing"
Unix and C can't really be "improved"
3. third will be improved to a point that is almost the right thing
2. second will condition its users to expect less
1. the worse-is-better software first will gain acceptance
I'm not sure about the compilation speed though