Я пытаюсь выучить некоторые CL самостоятельно, поэтому я предоставлю лучший ответ, который смогу. Common Lisp - это язык Dynami c по сравнению с языком STATI c. Для языка * stati c проверьте Haskell - он выполняет кучу проверок времени компиляции, чтобы убедиться, что типы совпадают для всех функций, и дает вам знать, если он выходит из строя. Однако в Common Lisp вещи немного отличаются .
Однако в Common Lisp переменные не печатаются так, как в таких языках, как Java или C ++. То есть вам не нужно объявлять тип объекта, который может содержать каждая переменная. Вместо этого переменная может содержать значения любого типа, а значения содержат информацию о типе, которую можно использовать для проверки типов во время выполнения. Таким образом, Common Lisp динамически типизирован - ошибки типа обнаруживаются динамически. Например, если вы передадите в функцию + что-то отличное от числа, Common Lisp сообщит об ошибке типа. С другой стороны, Common Lisp является строго типизированным языком в том смысле, что будут обнаружены все ошибки типов - нет способа трактовать объект как экземпляр класса, которым он не является.
Поэтому переменные, которые мы объявляем как аргументы функции, по умолчанию не имеют типа. Это может быть хорошим чтением для вас: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node15.html. В первом абзаце это выглядит следующим образом:
Важно отметить, что в Лиспе это типизированные объекты данных, а не переменные. Любая переменная может иметь любой объект Lisp в качестве значения. (Можно сделать явное объявление о том, что переменная на самом деле будет принимать только одно из ограниченного набора значений. Однако такое объявление всегда может быть опущено, и программа все равно будет работать правильно. Такое объявление просто представляет собой совет от пользователя, который может быть полезен для повышения эффективности. См. объявление.)
Поэтому, когда вы создаете свои функции, эти переменные могут иметь любой объект Lisp в качестве значения.
И если мы предпримем предприятие на Declare , мы увидим следующее:
Существует два различных использования объявления, один из которых объявить переменные Лиспа как «специальные» (это влияет на семантику соответствующих привязок переменных), а другой - дать совет, чтобы помочь системе Common Lisp (на самом деле компилятору) запускать ваш код на Lisp быстрее или с более сложными опциями отладки.
Наконец, если мы посмотрим на тип проверки , мы увидим:
сигналы проверки типа корректно Ошибка типа type-error, если содержимое места не относится к типу typepe c.
В обоих случаях для объявления и проверки типа мы даем системе Common Lisp рекомендации по типам и проверке типов. Давайте рассмотрим две предоставленные вами примеры функций.
Во-первых, «дискриминантная» функция использует функцию Declare для подтверждения того, что аргументы действительно являются числами и что компилятору не нужно их проверять. Функция осторожного распознавания использует check-type, чтобы убедиться, что каждая переменная действительно является числом, а затем выполняет операцию.
Вы можете спросить «Почему я должен беспокоиться об этом?», Где ответ предоставить либо более оптимизированную функцию (дискриминант), либо функцию, которая обеспечивает лучшую отладку и больше информации об ошибке (осторожно-дискриминант). Чтобы показать разницу, я запустил SBCL и определил обе функции. Затем я использовал дизассемблирование, чтобы показать машинный код каждого. Обратите внимание, что осторожный дискриминант выполняет больше проверок, чем дискриминант, что приводит к большему количеству машинного кода!
(дизассемблирует # 'дискриминант)
; disassembly for DISCRIMINANT
; Size: 83 bytes. Origin: #x10023700D7 ; DISCRIMINANT
; 0D7: 498B5D10 MOV RBX, [R13+16] ; thread.binding-stack-pointer
; 0DB: 48895DF8 MOV [RBP-8], RBX
; 0DF: 840425F8FF1020 TEST AL, [#x2010FFF8] ; safepoint
; 0E6: 488B55E8 MOV RDX, [RBP-24]
; 0EA: 488B7DE8 MOV RDI, [RBP-24]
; 0EE: FF1425C0000020 CALL QWORD PTR [#x200000C0] ; GENERIC-*
; 0F5: 488955D8 MOV [RBP-40], RDX
; 0F9: 488B55F0 MOV RDX, [RBP-16]
; 0FD: BF08000000 MOV EDI, 8
; 102: FF1425C0000020 CALL QWORD PTR [#x200000C0] ; GENERIC-*
; 109: 488B7DE0 MOV RDI, [RBP-32]
; 10D: FF1425C0000020 CALL QWORD PTR [#x200000C0] ; GENERIC-*
; 114: 488BFA MOV RDI, RDX
; 117: 488B55D8 MOV RDX, [RBP-40]
; 11B: FF1425B8000020 CALL QWORD PTR [#x200000B8] ; GENERIC--
; 122: 488BE5 MOV RSP, RBP
; 125: F8 CLC
; 126: 5D POP RBP
; 127: C3 RET
; 128: CC10 INT3 16 ; Invalid argument count trap
NIL
(дизассемблирует #' осторожный дискриминант)
; disassembly for CAREFUL-DISCRIMINANT
; Size: 422 bytes. Origin: #x10023701E3 ; CAREFUL-DISCRIMINANT
; 1E3: 4D8B4510 MOV R8, [R13+16] ; thread.binding-stack-pointer
; 1E7: 4C8945F8 MOV [RBP-8], R8
; 1EB: 840425F8FF1020 TEST AL, [#x2010FFF8] ; safepoint
; 1F2: EB44 JMP L1
; 1F4: 660F1F840000000000 NOP
; 1FD: 0F1F00 NOP
; 200: L0: 488B7DF0 MOV RDI, [RBP-16]
; 204: 4883EC10 SUB RSP, 16
; 208: 488B1571FFFFFF MOV RDX, [RIP-143] ; 'A
; 20F: 488B3572FFFFFF MOV RSI, [RIP-142] ; 'NUMBER
; 216: 4C894DD8 MOV [RBP-40], R9
; 21A: 488B056FFFFFFF MOV RAX, [RIP-145] ; #<SB-KERNEL:FDEFN SB-KERNEL:CHECK-TYPE-ERROR>
; 221: B906000000 MOV ECX, 6
; 226: 48892C24 MOV [RSP], RBP
; 22A: 488BEC MOV RBP, RSP
; 22D: FF5009 CALL QWORD PTR [RAX+9]
; 230: 4C8B4DD8 MOV R9, [RBP-40]
; 234: 488955F0 MOV [RBP-16], RDX
; 238: L1: 840425F8FF1020 TEST AL, [#x2010FFF8] ; safepoint
; 23F: 488B45F0 MOV RAX, [RBP-16]
; 243: 448D40F1 LEA R8D, [RAX-15]
; 247: 41F6C001 TEST R8B, 1
; 24B: 7512 JNE L2
; 24D: 4180F80A CMP R8B, 10
; 251: 740C JEQ L2
; 253: 41F6C00F TEST R8B, 15
; 257: 75A7 JNE L0
; 259: 8078F129 CMP BYTE PTR [RAX-15], 41
; 25D: 77A1 JNBE L0
; 25F: L2: EB47 JMP L4
; 261: 660F1F840000000000 NOP
; 26A: 660F1F440000 NOP
; 270: L3: 488B7DE8 MOV RDI, [RBP-24]
; 274: 4883EC10 SUB RSP, 16
; 278: 488B1519FFFFFF MOV RDX, [RIP-231] ; 'B
; 27F: 488B3502FFFFFF MOV RSI, [RIP-254] ; 'NUMBER
; 286: 4C894DD8 MOV [RBP-40], R9
; 28A: 488B05FFFEFFFF MOV RAX, [RIP-257] ; #<SB-KERNEL:FDEFN SB-KERNEL:CHECK-TYPE-ERROR>
; 291: B906000000 MOV ECX, 6
; 296: 48892C24 MOV [RSP], RBP
; 29A: 488BEC MOV RBP, RSP
; 29D: FF5009 CALL QWORD PTR [RAX+9]
; 2A0: 4C8B4DD8 MOV R9, [RBP-40]
; 2A4: 488955E8 MOV [RBP-24], RDX
; 2A8: L4: 840425F8FF1020 TEST AL, [#x2010FFF8] ; safepoint
; 2AF: 488B45E8 MOV RAX, [RBP-24]
; 2B3: 448D40F1 LEA R8D, [RAX-15]
; 2B7: 41F6C001 TEST R8B, 1
; 2BB: 7512 JNE L5
; 2BD: 4180F80A CMP R8B, 10
; 2C1: 740C JEQ L5
; 2C3: 41F6C00F TEST R8B, 15
; 2C7: 75A7 JNE L3
; 2C9: 8078F129 CMP BYTE PTR [RAX-15], 41
; 2CD: 77A1 JNBE L3
; 2CF: L5: EB3D JMP L7
; 2D1: 660F1F840000000000 NOP
; 2DA: 660F1F440000 NOP
; 2E0: L6: 498BF9 MOV RDI, R9
; 2E3: 4883EC10 SUB RSP, 16
; 2E7: 488B15B2FEFFFF MOV RDX, [RIP-334] ; 'C
; 2EE: 488B3593FEFFFF MOV RSI, [RIP-365] ; 'NUMBER
; 2F5: 488B0594FEFFFF MOV RAX, [RIP-364] ; #<SB-KERNEL:FDEFN SB-KERNEL:CHECK-TYPE-ERROR>
; 2FC: B906000000 MOV ECX, 6
; 301: 48892C24 MOV [RSP], RBP
; 305: 488BEC MOV RBP, RSP
; 308: FF5009 CALL QWORD PTR [RAX+9]
; 30B: 4C8BCA MOV R9, RDX
; 30E: L7: 840425F8FF1020 TEST AL, [#x2010FFF8] ; safepoint
; 315: 458D41F1 LEA R8D, [R9-15]
; 319: 41F6C001 TEST R8B, 1
; 31D: 7513 JNE L8
; 31F: 4180F80A CMP R8B, 10
; 323: 740D JEQ L8
; 325: 41F6C00F TEST R8B, 15
; 329: 75B5 JNE L6
; 32B: 418079F129 CMP BYTE PTR [R9-15], 41
; 330: 77AE JNBE L6
; 332: L8: 4C894DD8 MOV [RBP-40], R9
; 336: 488B55E8 MOV RDX, [RBP-24]
; 33A: 488B7DE8 MOV RDI, [RBP-24]
; 33E: FF1425C0000020 CALL QWORD PTR [#x200000C0] ; GENERIC-*
; 345: 488955E0 MOV [RBP-32], RDX
; 349: 4C8B4DD8 MOV R9, [RBP-40]
; 34D: 488B55F0 MOV RDX, [RBP-16]
; 351: BF08000000 MOV EDI, 8
; 356: FF1425C0000020 CALL QWORD PTR [#x200000C0] ; GENERIC-*
; 35D: 4C8B4DD8 MOV R9, [RBP-40]
; 361: 498BF9 MOV RDI, R9
; 364: FF1425C0000020 CALL QWORD PTR [#x200000C0] ; GENERIC-*
; 36B: 488BFA MOV RDI, RDX
; 36E: 4C8B4DD8 MOV R9, [RBP-40]
; 372: 488B55E0 MOV RDX, [RBP-32]
; 376: FF1425B8000020 CALL QWORD PTR [#x200000B8] ; GENERIC--
; 37D: 4C8B4DD8 MOV R9, [RBP-40]
; 381: 488BE5 MOV RSP, RBP
; 384: F8 CLC
; 385: 5D POP RBP
; 386: C3 RET
; 387: CC10 INT3 16 ; Invalid argument count trap
NIL
Как видно здесь, Common Lisp также может быть скомпилирован, что смущает некоторых людей. Лучше ответ здесь: Как Lisp dynamici c и скомпилирован? .