Categorías: Todo - security - functions - programming

por Yin Wang hace 11 años

25463

Yin's Mid-Term Memory

The text delves into various topics, starting with a critical analysis of the film "Escape from Alcatraz," questioning the plausibility of certain elements depicted in the movie, particularly the security measures at the prison and the intelligence required for an escape.

Yin's Mid-Term Memory

Yin's Mid-Term Memory

Tools

Unix shell tricks
Trick 1: change PATH in a rational way

... 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 }

Principles

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!

Unix shell is not well designed

But some clever tricks exist when you really need to use it in a neat way

TeXmacs

Computer Science

Programming Languages (basics)
Operating Systems
Data Structures

Recommended Readings

Dunning-Kruger effect
"Why People Fail to Recognize Their Own Incompetence"
VIDEO: William Clinger: Compiler Optimization for Symbolic Languages (1987)
basic points

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

'()

a student of Carl Hewitt

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

William Clinger, author of Larceny
Andrew W Appel. Intensional equality ;-) for continuations. ACM SIGPLAN Notices 31(2), February 1996, pages 55-57.
But they can optimize away the call when 'quickroot' is defined in the same file
None of my compilers do this optimization (interprocedual)

Racket

larceny

Ikarus

clang -O3

gcc -O3

spacepen
In Praise of Idleness (Bertrand Russell)
audio
text
"The Development of Chez Scheme" by R. Kent Dybvig
most of the techniques mentioned in his paper has been taught by him in his compiler class P523
got a PhD from UNC

was not happy at UNC

Dybvig was in Dan Friedman's class

Clojure Notes

Ideas

Unit Tests
new way

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

Current use of unit tests are not convenient

tests are separated from code

Fun Stuff

Alcatraz
related films

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

Faster-Than-Light
Future Timeline
Map of the Universe

New

Scala
brace syntax for lambdas

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"

using the function name itself as call with no arguments

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

real-world C/C++ problems
fixed size stack of C/C++ causing too much complexity in recursive code

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 evil of const annotations

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"

Typed Racket comments
known-length list type constructor

(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))

variable-arity functions

pass lists instead

Should not have variable arity functions

parametric polymorphism

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

intersection types

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))

type inference

Is unification-based type inference still usedful sometimes?

has only forward type inference

syntax is a little ugly + confusing

(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

... or it makes sense but too complicated

> 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)))])))

... or if the error message doesn't make sense

> 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)))])))

... but no so nice if you can't detect errors like this:

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)))])))

Union types are nice

Should Tree? be defined after the union type?

(define-type Tree (U leaf node)) (struct: leaf ([val : Number])) (struct: node ([left : Tree] [right : Tree]))

about R7RS Scheme draft (may apply to R6RS etc also)
Why is 'case' derived form?

Can be implemented in a more efficient way than nested if's

case = switch in C

Why is 'cond' "derived form" ?

but it is more general than if

It can be expressed by nested if's

Praise for define-record-type

definitely needs something like that in the "small" language

much simpler than R6RS

CLR v.s. JVM
CLR provides a tail call instruction

Is there really a need for a "tail call" instruction?

The CLR provides support for declaring and manipulating pointers.

provides a "pinning" mechanism so that developers can declare a block of code within which the CLR is not allowed to move certain pointers

The CLR allows user code to define new value types (structs), whereas the JVM provides a fixed collection of value types (byte, short, int, long, float, double, char, boolean) and only allows users to define new reference-types (classes).
The CLR has coroutines (implemented with the C# 'yield' keyword). The JVM does not.
The CLR has closures (implemented as C# delegates). The JVM does not.

Closures and generators are implemented at a language level and are simply represented as classes on the CLR level.

MSIL instructions are polymorphic (add two values) and the JIT compiler is responsible for determining the types of the operands and creating appropriate machine code

In the JVM, every unique operation (add two int values, add two float values, etc) has its own unique instruction.

You can't overload Java methods on generic types. You can't have two different methods, with the same name, differing only on whether they accept a List or a List.

Since the CLR knows about parametric types, it has no problem handling methods overloaded on generic type specializations.

The JVM has no notion of which classes have type-arguments, and it's unable to perform parametric specializations at runtime
CLR includes instructions for creating generic types, and then for applying parametric specializations to those types. So, at runtime, the CLR considers a List to be a completely different type from a List

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 generates completely different code from List

Chinese Puzzles
I have the middle on
Ingenious Rings (Qiao huan 巧环)
http://xkcd.com/297/
Rise of Worse is Better - Richard Gabriel
Richard Gabriel was wrong

They will never get close to the "right thing"

Unix and C can't really be "improved"

Unix and C are the ultimate computer viruses

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

Larceny - another fast Scheme implementation
Benchmarks are a crock
Larceny is sometimes faster than Chez (sometimes slower)

I'm not sure about the compilation speed though

Benchmarks of several Scheme implementations
Ikarus Scheme
bootstraps itself in 7 seconds
Cisco Systems acquires Chez Scheme