Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

Static Type Signature Syntax for a Lisp

Name: Anonymous 2013-12-14 17:42

How would you implement it without breaking homoiconicity?

Name: Anonymous 2013-12-14 18:18

Common Lisp is already statically typed.

I'm not a Schemer but apparently there's something called Typed Racket.

Name: Anonymous 2013-12-14 19:49


(declaim (ftype (function ((unsigned-byte 64)) (values (unsigned-byte 64) &optional))
                shuffle))
(defun shuffle (x)
  (flet ((one-round (x mask shift)
           (ldb (byte 64 0)
                (logior (ash (logand x mask) shift)
                        (logand (ash x (- shift)) mask)
                        (logandc2 x (logior mask (ash mask shift)))))))
    (declare (inline one-round))
    (let* ((k1 (one-round x  #x00000000FFFF0000 16))
           (k2 (one-round k1 #x0000FF000000FF00  8))
           (k3 (one-round k2 #x00F000F000F000F0  4))
           (k4 (one-round k3 #x0C0C0C0C0C0C0C0C  2))
           (k5 (one-round k4 #x2222222222222222  1)))
      k5)))

CL-USER> (format t "~2r~%" (shuffle #x00000000FFFFFFFF))
101010101010101010101010101010101010101010101010101010101010101

CL-USER> (disassemble 'shuffle)
; disassembly for SHUFFLE
; Size: 424 bytes
; 05772DB0:       488D0409         LEA RAX, [RCX+RCX]         ; no-arg-parsing entry point
;      DB4:       4823054D010000   AND RAX, [RIP+333]         ; #x1FFFE0000
;      DBB:       488BD0           MOV RDX, RAX
;      DBE:       48C1E210         SHL RDX, 16
;      DC2:       488BC1           MOV RAX, RCX
;      DC5:       48C1E810         SHR RAX, 16
;      DC9:       48D1E0           SHL RAX, 1
;      DCC:       48230535010000   AND RAX, [RIP+309]         ; #x1FFFE0000
;      DD3:       4809C2           OR RDX, RAX
;      DD6:       488BD9           MOV RBX, RCX
;      DD9:       48231D30010000   AND RBX, [RIP+304]         ; #xFFFF00000000FFFF
;      DE0:       488BC2           MOV RAX, RDX
;      DE3:       48D1F8           SAR RAX, 1
;      DE6:       4809D8           OR RAX, RBX
;      DE9:       488D1400         LEA RDX, [RAX+RAX]
;      DED:       48231524010000   AND RDX, [RIP+292]         ; #x1FE000001FE00
;      DF4:       488BDA           MOV RBX, RDX
;      DF7:       48C1E308         SHL RBX, 8
;      DFB:       488BD0           MOV RDX, RAX
;      DFE:       48C1EA08         SHR RDX, 8
;      E02:       48D1E2           SHL RDX, 1
;      E05:       4823150C010000   AND RDX, [RIP+268]         ; #x1FE000001FE00
;      E0C:       4809D3           OR RBX, RDX
;      E0F:       488BD0           MOV RDX, RAX
;      E12:       48231507010000   AND RDX, [RIP+263]         ; #xFF0000FFFF0000FF
;      E19:       488BC3           MOV RAX, RBX
;      E1C:       48D1F8           SAR RAX, 1
;      E1F:       4809D0           OR RAX, RDX
;      E22:       488D1400         LEA RDX, [RAX+RAX]
;      E26:       482315FB000000   AND RDX, [RIP+251]         ; #x1E001E001E001E0
;      E2D:       488BDA           MOV RBX, RDX
;      E30:       48C1E304         SHL RBX, 4
;      E34:       488BD0           MOV RDX, RAX
;      E37:       48C1EA04         SHR RDX, 4
;      E3B:       48D1E2           SHL RDX, 1
;      E3E:       482315E3000000   AND RDX, [RIP+227]         ; #x1E001E001E001E0
;      E45:       4809D3           OR RBX, RDX
;      E48:       488BD0           MOV RDX, RAX
;      E4B:       482315DE000000   AND RDX, [RIP+222]         ; #xF00FF00FF00FF00F
;      E52:       488BC3           MOV RAX, RBX
;      E55:       48D1F8           SAR RAX, 1
;      E58:       4809D0           OR RAX, RDX
;      E5B:       488D1400         LEA RDX, [RAX+RAX]
;      E5F:       482315D2000000   AND RDX, [RIP+210]         ; #x1818181818181818
;      E66:       488D1C9500000000 LEA RBX, [RDX*4]
;      E6E:       488BD0           MOV RDX, RAX
;      E71:       48C1EA02         SHR RDX, 2
;      E75:       48D1E2           SHL RDX, 1
;      E78:       482315B9000000   AND RDX, [RIP+185]         ; #x1818181818181818
;      E7F:       4809D3           OR RBX, RDX
;      E82:       488BD0           MOV RDX, RAX
;      E85:       482315B4000000   AND RDX, [RIP+180]         ; #xC3C3C3C3C3C3C3C3
;      E8C:       488BC3           MOV RAX, RBX
;      E8F:       48D1F8           SAR RAX, 1
;      E92:       4809D0           OR RAX, RDX
;      E95:       488D1400         LEA RDX, [RAX+RAX]
;      E99:       482315A8000000   AND RDX, [RIP+168]         ; #x4444444444444444
;      EA0:       48D1FA           SAR RDX, 1
;      EA3:       48D1E2           SHL RDX, 1
;      EA6:       488BDA           MOV RBX, RDX
;      EA9:       488BD0           MOV RDX, RAX
;      EAC:       48D1EA           SHR RDX, 1
;      EAF:       48D1E2           SHL RDX, 1
;      EB2:       4823158F000000   AND RDX, [RIP+143]         ; #x4444444444444444
;      EB9:       48D1FA           SAR RDX, 1
;      EBC:       4809D3           OR RBX, RDX
;      EBF:       4823058A000000   AND RAX, [RIP+138]         ; #x9999999999999999
;      EC6:       4809C3           OR RBX, RAX
;      EC9:       48BA00000000000000C0 MOV RDX, -4611686018427387904
;      ED3:       4885DA           TEST RBX, RDX
;      ED6:       488D141B         LEA RDX, [RBX+RBX]
;      EDA:       740E             JEQ L0
;      EDC:       488BD3           MOV RDX, RBX
;      EDF:       4C8D1C256B090020 LEA R11, [#x2000096B]      ; ALLOC-UNSIGNED-BIGNUM-IN-RDX
;      EE7:       41FFD3           CALL R11
;      EEA: L0:   488BE5           MOV RSP, RBP
;      EED:       F8               CLC
;      EEE:       5D               POP RBP
;      EEF:       C3               RET

Name: Anonymous 2013-12-14 20:07

>>2
typed racket
(struct: pt ([x : Real] [y : Real]))
 
(: distance (pt pt -> Real))
(define (distance p1 p2)
  (sqrt (+ (sqr (- (pt-x p2) (pt-x p1)))
           (sqr (- (pt-y p2) (pt-y p1))))))


Not too bad, though the infix : operator seems a little un-lispy.

>>3

(declaim (ftype (function ((unsigned-byte 64)) (values (unsigned-byte 64) &optional))
                shuffle))

Jesus christ that's hideous.

Name: Anonymous 2013-12-14 20:14

>>4

Common Lisp always returns multiple values, hence the values form. I'm not sure what the rationale for the ftype is.

Also you shouldn't be declaring types all over the place.

Name: Anonymous 2013-12-14 22:44

>>5

ftype for the same reason as function elsewhere. You have to tell Lisp you're talking about the name in the function namespace, not the variable namespace.

Name: Anonymous 2013-12-15 5:00

>>2
Common Lisp is already statically typed.
With just one type for everything? Haha, losers.

Name: Anonymous 2013-12-15 5:12

>>7

No.


CL-USER> (defun square (x)
           (* x x))
SQUARE
CL-USER> (describe 'square)
COMMON-LISP-USER::SQUARE
  [symbol]

SQUARE names a compiled function:
  Lambda-list: (X)
  Derived type: (FUNCTION (T) (VALUES NUMBER &OPTIONAL))
  Source form:
    (SB-INT:NAMED-LAMBDA SQUARE
        (X)
      (BLOCK SQUARE (* X X)))
; No value
CL-USER> (defun square (x)
           (declare (type integer x))
           (* x x))
STYLE-WARNING: redefining COMMON-LISP-USER::SQUARE in DEFUN
SQUARE
CL-USER> (describe 'square)
COMMON-LISP-USER::SQUARE
  [symbol]

SQUARE names a compiled function:
  Lambda-list: (X)
  Derived type: (FUNCTION (INTEGER) (VALUES UNSIGNED-BYTE &OPTIONAL))
  Source form:
    (SB-INT:NAMED-LAMBDA SQUARE
        (X)
      (DECLARE (TYPE INTEGER X))
      (BLOCK SQUARE (* X X)))


Notice how the STATIC type (as understood by SBCL) changes when we add our declaration.

Name: Anonymous 2013-12-15 5:18

>>7

Are you the same HURR DURR WHATS A TYPE SYSTEM dumbfuck or one of the same dumbfucks (21, 25, 31, 32, 38, 40 or 46) from the other Lisp thread?

Cause if not then this place is full of dumbfucks

Name: Anonymous 2013-12-15 7:29

>>1
How would you implement it without breaking homoiconicity?
A useless question because lisp is dead. And good riddance.

Name: Anonymous 2013-12-15 8:21

CHECH EM DUBZ

Name: Anonymous 2013-12-15 13:40

>>9
Of course this place is full of dumbfucks - Lisp dumbfucks who don't understand why static typechecking is a must in any serious language.

Name: Anonymous 2013-12-15 18:28

>>12
But Lisp implementations have had static type checking for DECADES, and Common Lisp at least has a more powerful type system than any language I know of.

Name: Anonymous 2013-12-15 18:42

>>7

There is a difference between having 0 types and having 1 type that you have managed to overlook somehow.  I do not understand how this is possible, but it appears that you have somehow managed to believe that a system with a single static type is equivalent to not knowing the type at all.  Since this is rather incredulous to me, let me at least try to explain this so that those who understand both you and me can explain it to you.

Suppose we have a machine with /n/ native types each with their set of operations (which is how this whole type thing began). Values of each disjoint type may freely share binary representation; operations only work on untyped bits and it is the programmer's responsibility to give them the right values to operate on. The fundamental observation was that while memory is untyped, the operations are typed and yield bad results if given values that were expected to be of a different type than they actually are, but the computer was utterly unable to report any of this as a problem because by the time the operations got their values, the binary representation was assumed to be that of the type the operations had advertised that they required.  The reason for the compile-time type analysis is precisely that the execution of the program has no idea whatsoever which of the many types that map onto to the binary representation the actual value in memory is of, and the kind of mistakes that were made in the past when programmers had to keep track of this thing by hand was very expensive.  So instead of the programmer having to keep the proper type in mind, the compiler would ensure that a binary representation of an object only had one meaning, and they did this by making the memory have type, too, not just the operations, however fleetingly in the compiler's view. Suppose further that all the values you could possibly think of are representable using those /n/ types.  In this perfect world, there would be no need for any run-time type dispatch or checking at all, and every programmer would instantly revere the static type analysis.

Now suppose you want to add an additional type to your programs, one which is not supported by the hardware operations.  Because of the nature of the computer, it will necessarily require a both a binary representation that could be mistaken for some of the native types and a set of operations that work on this binary representation that are now defined by the programmer.  If you insist on the hardware view of your computer, you will now create a virtual or abstract type, and you will inform your compiler of your construction. It will use the exact same methods it used to keep binary representations of native types from being confused or conflated, and you will never give any of your new, virtual values to an operation that requires a native type, nor mistake a native value for your new, virtual type.  Meanwhile, in the memory of the computer running your program, there will be a binary representation of an object that does not correspond to any of the machine's own types and whose meaning it is now even more impossible for anyone who looks only at the memory to determine than if they were native types.

Now suppose you add two varieties of an abstract type upon which a number of operations exhibit no variation, but at least one does. This situation is qualitatively different from the native types, for the hardware uses disjoint types.  The solution to this problem that is not qualitatively different is to duplicate the functionality for the two varieties and continue to keep them disjoint.  However, as you realize that they are interchangeable in some respects, you have to add code to support the interchangeability.  This way of implementing abstract types is extremely artificial, however, and breaks completely with the old way of doing things -- any sane programmer would conflate the two varieties and consciously break the type disjointness. And so the run-time type dispatch is born as the qualitatively different solution.

Since the compiler is now instructed to treat two types as the same, which they actually are not, the language or the programmer must add the type-distinguishing information to the binary representation one way or another and add operations that are usedly only to distinguish types from eachother.  Building a harness for this meta-information is not the trivial job you think it is with your «0 lines of code».  In fact, meta-information fundamentally contradicts the hardware view of native values, for in the hardware view, a value exists only as the input parameter of some computational operation.  In order for the meta-information paradigm to work, we now have to attach meaning to the fact that two innocuous native values subtract to zero.  We must never regard these values we use for this purpose as numeric -- they are only to be used for their equality with known values, or identity.

It is vitally important at this point to realize that the type-distinguishing meta-information is not used to /check/ the types of arguments, but is used to /dispatch/ on them, selecting the operation according to the type of the value.

Suppose we have built the type-dispatching harness for our abstract types such that we can freely add more abstract types, organize them into hierarchies of supertypes and subtypes, and share (or inherit) operations and properties alike in a web of types.  All functions that advertise that they accept values of a particular type know that they may also receive values of any of its subtypes and that even if they do not distinguish them from eachother, one of the functions it calls may. So functions that need to make special provisions for the types of its arguments are /generic/ and perform the exact same abstract operation on the abstract types, but different /concrete/ operations according to the types of the values.  For instance, all programming languages make the basic arithmetic operations generic over the whole spectrum of numeric types supported by the hardware, usually all the additional numeric types defined by the language and sometimes also the user-defined numeric types.  If we retain the type-checking of the compiler that we built for the native types to keep from confusing them, such as catching the obvious misuse of generic functions that only work on any of the various types of numbers, but not on any other supertypes, we now face both compile-time type checking and run-time type dispatch.  The compile-time restrictions on correct programs may very well reduce the amount of run-time dispatching, but all functions that /could/ accept any of the abstract types must be prepared to do type dispatching.

(Of course, one way to cheat in this process is to optimize away the type dispatching of a generic function and let the compiler call the type-specific function directly if it can determine the types to a useful degree at compile-time.  However, the mechanics of cheating tend to cloud the more central issues, so I just want to mention that it is often more natural to cheat than to do the right thing, which in no way reduces the responsibility to know what the right thing is.)

Now, since we have built this meta-information and type-dispatching harness and forced every function in the entire programming languageinto it, we face an engineering decision to retain the hardware-native types or to regard them as a special case of the general concept.  We also face a theoretical decision, even a philosophical one, in that we have to ask ourselves if there actually can exist disjoint types in the real world, or if disjointness is an artifice of the hardware that it is clearly easier to implement than one which wastes resources to check the types of its arguments.  The division of labor that is so evidently very intelligent in the design of hardware and software, is neither evident nor intelligent in the design of programming languages that are intended more for humans than for machines.

If we make the philosophical leap from hardware values to values that reflect the human view of the world, we immediately observe that there can be no such thing as disjoint types in reality -- disjointness of types is an artifice of our own desires and our own limitations in approaching the mass of information that is the real world observed by our brains.  Any categorization serves a purpose, and while it takes a genius most of the time to re-categorize for a different purpose, we must be aware of the purpose to which our categorization was designed if we are to avoid the extremely difficult problem of working at cross purposes with our conceptualization of the world we work in and on.

Being exceedingly intelligent and remarkably introspective, we look at our type systems and realize that there must exist a supertype of all types such that what appears to be disjointness is only disjointness for a particular purpose, and we realize intuitively that if there can be supertypes of all types, there must be subtypes of all types, and we invent the conceptual null type of which there are no values, but which is a subtype of all types, if for nothing else, then for the sake of mathematical completeness.  Disjointness is now in the eyes of the beholder, only, and any beholder is free to partition the value space into any categories that fit his purpose.  Our categorization is now not free of purpose -- it will always continue to have /some/ -- but it is now possible for the programmer to partition the entire set of machine-representable values into his own types any way he likes.

Name: Anonymous 2013-12-15 18:46

>>7

Common Lisp is not quite as abstract, but very close.  In Common Lisp, we observe that there is a supertype of all types, T, on which there are no useful operations, but which means that every function that has not advertised to the compiler that it only accepts a subset of the type space, must be prepared to perform type dispatch to weed out the types for which there exist no useful operation.  This process is evidenced in the construction of operations that branch out over the type space, incidentally.  COND, CASE, etc, all accept T as the final branch, T being that which is always true, the supertype of all types, etc.  I delight in this mathematical elegance.

This way of thinking necessarily differs from the artificial, disjoint thinking.  We regard the generic operations we define as having well-defined semantics for a subset of the available types, so if they are invoked on values of any other types, we expect that this condition is handled exceptionally.  If we define operations that can only, ever, accept values of an a priori set of types, we communicate this to the compiler and expect it to help us avoid mistakes, but in general, we regard the categorization that we employ to model and understand the world we program in and for, as a posteriori, and we do not make the common mistake of believing that what we already know is all that we can possibly know.  As a consequence, it is a design mistake in Common Lisp to write functions that expect only very specific types to the exclusion of other natural types and values.

To illustrate just how type-flexible Common Lisp is, the standard has the concept of a designator for a type.  Most Common Lisp functions that take only string arguments are not defined merely on strings, but on designators for strings, which means that they can be called with a character which is a designator for a strong of length 1, or a symbol which is a designator for the string that is its name.  Whereas most programming languages have rich libraries of string functions, Common Lisp defines a rich library of functions that work on sequences of any kind: lists, vectors, strings.  A language in the disjoint tradition may provide one function to search for a character in a string, one function to search for substrings in strings, and another to search a vector of characters for a character.  Common Lisp defines the generic function SEARCH which accepts sequences of any type and returns the position of the match.  This genericity is so common in Common Lisp that the traditional meaning is regarded as ubiquitous and therefore not in need of special mention.  Instead, «generic function» is a new kind of function which allows programmer-defined methods to be defined on particular programmer-defined classes of arguments, but this should not be interpreted to mean that normal Common Lisp functions are not just as generic in the traditional sense.

A request for more static type checking in Common Lisp is regarded as a throw-back to the times before we realized that disjointness is in the eye of the beholder, or as a missing realization that disjointness does not exist in the real world and therefore should not exist in the virtual world we create with our software.  Just because computers are designed a particular way that makes certain types of values much more efficient to compute with than others, does not mean that efficiency is /qualitative/.  Efficiency is only quantitative and subordinate to correctness.  It is a very serious error in the Common Lisp world to write a function that returns the wrong result quickly, but does notknow that it was the wrong result.  For this reason, type correctness is considered to be the responsibility of the function that makes the requirements, not of the caller or the compiler.  If the programmer who makes those requirements is sufficiently communicative, however, the compiler should come to his assistance.  The default behavior, on the other hand, is that functions have to accept values o type T.

Name: Anonymous 2013-12-16 3:10

Put type tags in the CPU so the instructions get the type from the operands instead of the opcode. That's what Lisp machines did. This ``dynamic typing is slow'' faggotry is all because you're using a crap CPU that isn't designed for dynamic typing.

Name: Anonymous 2013-12-16 13:38

>>14,15
Wow, what a bunch of word-baloney that misses the one all-important point: (a) static typechecking is a must for practical programming because of error-checking, documentation and low-level optimization, (b) type declarations are an extremely useful form of metadata (both to the compiler and the programmer) independent of machine representations  and (c) subtyping is a terrible killer of type inference and is actually largely unuseful because it creates unnecessary entanglement.
And what you call "disjoint" types is actually a necessary ingredient in type expressivity. Being able to declare that a certain type is to be used ONLY in certain places is no less useful than being able to declare what these certain places are. Dynamic type-checking is a sorry excuse for the language not being expressive enough to delineate the disjointness of the types of all terms clearly enough.

Name: Anonymous 2013-12-16 17:39

>>17

*shrug* I give up. pearls before swine and all that. I give you a good coherent argument and you give me "but but but my shitty compiler (very likely to be GHC) can't do inference when there's subtypes!!!" (lol at your troll compiler) and again "but but but if you have dynamic types then you don't have static types!!!" (really how fucking stupid are you? I've stated in like a million different ways that (in Common Lisp, but also other dynamic languages which adopt similar strategies) that you have static types, they're still there, the compiler is still free to use them for error checking and low-level optimization, and their declaration is documentation or whatever. Why do you keep ignoring this?)

You win. You can't possibly lose when you refuse to understand what the other person says. Enjoy your strongly hyped, purely fictional, weird BSDM shitlangs.

Name: Anonymous 2013-12-16 20:37

big black cock (BBC)

Name: Anonymous 2013-12-17 13:08

>>18
but but but my shitty compiler (very likely to be GHC) can't do inference when there's subtypes!!!
Type inference is undecidable, you clown. That's why Java and C++ don't have it.

they're still there, the compiler is still free to use them for error checking and low-level optimization
Except that it can't when there's not enough declarations. And there are always shit coders in Indian bodyshops that will write without type declarations, and your code will have to interact with unityped (which is the same as untyped for practical purposes) code.

Try to do static array bound check elimination in Lisp. Oh, I forgot, with Lisp runtime has to check the type of every element of every collection, so if you want to add two arrays with billions of floats in them, Lisp has to check types billions of times.

Name: Anonymous 2013-12-17 13:30

>>20
Try to do static array bound check elimination in Lisp. Oh, I forgot, with Lisp runtime has to check the type of every element of every collection, so if you want to add two arrays with billions of floats in them, Lisp has to check types billions of times.
That's why you use a Lisp machine. Your CPU is designed for paging and running programs in separate address spaces. Imagine running Unix on a system with no virtual addressing that had to swap the entire process memory to disk and read in a new process instead of just switching the page tables. Pretty inefficient, eh? That's the same with Lisp. Just like Unix/VMS/Windows machines have hardware to run processes in separate address spaces, Lisp machines have hardware to check the types and bounds of arrays. This bounds checking is Lisp's memory protection model.

Name: Anonymous 2013-12-17 13:44

>>21
The Lisp Machine is an old, tried and failed project just like Lisp AI. Deal with it and stop dreaming.

Name: Anonymous 2013-12-17 17:19

>>20

Yet my Lisp still does type inference, even in the presence of subtypes.

And stop spreading lies! What you want is easy to do e.g. (declare (type array float (100))). Now if you have declared a high enough optimize speed value and low enough safety value, your compiler will probably emit some very fast code.

The reason  this isn't done all the time is because maybe one day I'll have e.g. complex numbers in my array and I don't want to have to change 690 declarations in 69 functions cause of my earlier shorted sightedness, nor should I, nor should any programmer worth his salt.

Unlike languages you might be used to, Common Lisp trusts the programmer. For example there's no way to make symbols (i.e. classes, functions, generic functions, variables, conditions, restarts) truly "private" in a package; You can only mark them as not automatically exported, but the client is free to explicitly import them, or otherwise access them if they wish.

Another example is "advising functions". This refers to, dynamically (as in dynamic scope), "advising" an existing function to execute program text before or after it is called, without modifying the program text where it is called.

So it's not a matter of bad "indian body shop" programmers not declaring types all over the place and wrecking havoc for everyone, rather, it's good Common Lisp programmers that don't declare types unless they have a very good reason to limit what clients of their programs can do with that program.

I know for someone who has not yet experienced the pure bliss of writing large systems in Common Lisp, and who has been so thoroughly sold the "Now now son if I gave you a chain saw to cut that tree, you'd only cut your hands of too" nanny programming mentality, a lot of this sounds like gobbledigook. But it's not. Just try it, otherwise please stop spreading lies about Common Lisp (e.g. Common Lisp is not statically typed or Common Lisp can't do static type checking, or Common Lisp can't optimize my array function. These are lies). It's a dishonest thing to lie.

>>22

Two good examples of "dead" Lisp AIs are Computer Algebra Systems, and proof assistants. They are so dead that I use them all the time.

Another good example is unification and knowledge representation. So dead. Completely useless. Dead. Forgotten. Why would anyone want to do this?

And the (Symbolics) Lisp machine may be out of business, but that doesn't stop it from having existed. That doesn't stop it from still, to this day, being the finest operating system and development environment ever created. Nothing has topped it.

Name: Anonymous 2013-12-18 2:10


(declaim (ftype (function ((simple-array single-float (1000))
                           (simple-array single-float (1000)))
                          (values (simple-array single-float (1000)) &optional))
                silly-addition))

(defun silly-addition (array1 array2)
  (let ((result (make-array 1000 :element-type 'single-float)))
    (declare (type (simple-array single-float (1000)) result))
    (dotimes (i 1000 result)
      (declare (type fixnum i))
      (setf (aref result i) (+ (the single-float (aref array1 i))
                               (the single-float (aref array2 i)))))))

CL-USER> (disassemble 'silly-addition)

; disassembly for SILLY-ADDITION
; Size: 151 bytes
; 055E7C62:       B8D5000000       MOV EAX, 213               ; no-arg-parsing entry point
;       67:       B9D0070000       MOV ECX, 2000
;       6C:       BEE8030000       MOV ESI, 1000
;       71:       488D14B51F000000 LEA RDX, [RSI*4+31]
;       79:       4883E2F0         AND RDX, -16
;       7D:       49896C2440       MOV [R12+64], RBP
;       82:       4D8B5C2418       MOV R11, [R12+24]
;       87:       4C01DA           ADD RDX, R11
;       8A:       4939542420       CMP [R12+32], RDX
;       8F:       7658             JBE L4
;       91:       4989542418       MOV [R12+24], RDX
;       96:       498BD3           MOV RDX, R11
;       99: L0:   488D520F         LEA RDX, [RDX+15]
;       9D:       488942F1         MOV [RDX-15], RAX
;       A1:       48894AF9         MOV [RDX-7], RCX
;       A5:       49316C2440       XOR [R12+64], RBP
;       AA:       7402             JEQ L1
;       AC:       CC09             BREAK 9                    ; pending interrupt trap
;       AE: L1:   31C9             XOR ECX, ECX
;       B0:       EB28             JMP L3
;       B2:       660F1F840000000000 NOP
;       BB:       0F1F440000       NOP
;       C0: L2:   F30F104C4B01     MOVSS XMM1, [RBX+RCX*2+1]
;       C6:       F30F10544F01     MOVSS XMM2, [RDI+RCX*2+1]
;       CC:       F30F58D1         ADDSS XMM2, XMM1
;       D0:       F30F11544A01     MOVSS [RDX+RCX*2+1], XMM2
;       D6:       4883C102         ADD RCX, 2
;       DA: L3:   4881F9D0070000   CMP RCX, 2000
;       E1:       7CDD             JL L2
;       E3:       488BE5           MOV RSP, RBP
;       E6:       F8               CLC
;       E7:       5D               POP RBP
;       E8:       C3               RET
;       E9: L4:   492B542418       SUB RDX, [R12+24]
;       EE:       52               PUSH RDX
;       EF:       BA305B4200       MOV EDX, 4348720           ; alloc_tramp
;       F4:       FFD2             CALL RDX
;       F6:       5A               POP RDX
;       F7:       EBA0             JMP L0

CL-USER> (defparameter *a* (make-array 1000
                                       :element-type 'single-float
                                       :initial-contents
                                       (loop for i from 0 below 1000
                                             collect (random 1.0f0))))

;; Same for B

CL-USER> (time (dotimes (i 1000000) (silly-addition *a* *b*)))
Evaluation took:
  1.750 seconds of real time
  1.830000 seconds of total run time (1.830000 user, 0.000000 system)
  [ Run times consist of 0.287 seconds GC time, and 1.543 seconds non-GC time. ]
  104.57% CPU
  4,671,423,259 processor cycles
  4,015,683,312 bytes consed

Name: Anonymous 2013-12-18 2:16

That's SBCL with (declaim (optimize (compilation-speed 0) (debug 0) (safety 0) (space 0) (speed 3))).

I'm no Lisp optimization expert tho.

The whole example is rly stupid too.

Name: Anonymous 2013-12-18 12:20

>>14
It is vitally important at this point to realize that the type-distinguishing meta-information is not used to /check/ the types of arguments, but is used to /dispatch/ on them, selecting the operation according to the type of the value.

How does one contradict the other? How does dispatch on types contradict forbidding programs with inconsistent types to be compiled?

Name: Anonymous 2013-12-18 12:26

>>23
OK, I'll try it. For one thing, the condition and restart system looks very good. Macros look like a terrible bug-bag though, being so raw, low-level and totally undebuggable with all those gensyms.

Name: Anonymous 2013-12-18 18:03

>>27

Thank you.

The best way to learn the language is probably following along with "Practical Common Lisp" and double checking everything Siebel writes with the Hyperspec. After that read any parts of the Hyperspec you didn't following Siebel. This is the best way to learn the language itself, but is very dry. So start working on something immediately too.

The best way to learn how to solve problems in the language is Paradigms of Artificial Intelligence Programming (but this book doesn't teach the language itself very well (many times the author sacrifices accuracy and correctness with "getting the point across" e.g. in the first chapter he makes no distinction between macros and special forms (calling both special forms))).

Also, Common Lisp is not really optimized for small programs; For small programs, Common Lisp programs look very verbose next to similar programs in some other languages. If all you ever do is write small programs, then Common Lisp, while it will still be fun to use, probably won't offer much of an advantage over other halfway decent languages.

You are correct to be cautious about macros. However, they're not as difficult to debug as they may seem at first: For example you have macroexpand-1 and Lisp editors often have this bound to a button so e.g. I can C-RET on some macro in my source, and a new window will pop up with its expansion; then I can C-RET on other macros within that window, and so on till I get to where I need. Lisp implementations that also implement CLTL2 might provide macroexpand-all or your editor might provide something similar. Furthermore, the package system really helps with writing macros. If you write a macro in package foo, then if it uses a symbol barit is really using the symbol foo::bar, and in a package baz, it won't shadow or interfere with a symbol of the same name i.e. baz::bar (unless you exported bar, and baz imported it). There's also the high level hygeine abstractions with-gensyms and once-only available in e.g. Alexandria and described in many books.

Name: Anonymous 2013-12-18 18:07

>>26

You are correct. There is no contradiction with the two things you described.

There is a contradiction, however, between compilers that do type erasure and compilers that tag all types.

Name: Anonymous 2013-12-20 10:26

I'm not at all means a LISPer so what I'm suggesting could be incredibly idiotic, for that I apologize. But why not something like this?
(defun plus ((int a) (int b)) (+ a b))

so it would be like:

(defun <NAME> ((type1 arg1) .. (typen argn)) (<BODY>))

Name: Anonymous 2013-12-20 19:58

Name: Anonymous 2013-12-20 20:54

>>30

Doesn't assert the return type

Name: Anonymous 2013-12-20 21:47

i have a big black cock

Don't change these.
Name: Email:
Entire Thread Thread List