把函數式編程語言寫得和彙編一樣是一番怎樣的感受?

RT

有感而發最近看同事寫的代碼(當初還是他建議在項目中引入OCaml的),不用pattern matching而大量用if,用matching + if去多次匹配tuple中的各個元素,大量複製粘貼函數修改而不採用高階函數的方式,此外大量使用iter以及計數的方式進行操作。。。。最不能忍的是沒有注釋和換行。。

===

抱歉我標題黨了


是不是這樣的

program :: [Word8]
program = asm 0x8000 $ do
ldai 0
clc
incloop &<- here adci 1 cmpi 0xf0 bne incloop forever &<- here jmp forever

Ref: An ASM Monad


比如這樣?

(defun mkasm16-bios-bootloader (image-size load-address optional (skip-sectors 0))
(let* ((first-sector (1+ skip-sectors))
(last-sector (+ first-sector (ceiling image-size +sector-size+)))
(read-buffer-segment (floor +read-buffer+ #x10)))
`((:jmp (:pc+ 0)) ; some BIOSes might check for this.
;;
;; We are running at address #x7c00.
;;
(:xorw :ax :ax)
(:movw :ax :ds)
(:movw :ax :es)

(:movw #x9000 :ax)
(:movw :ax :ss)
(:movw #xfffc :bp)
(:leaw (:bp ,(- +stack-frame-size+)) :sp)
(:movw "welcome :si) ; Print welcome message)
(:callw "print)

;;
;; Enable the A20 gate
;;
(:callw "empty-8042)
(:movb #xd1 :al)
(:outb :al #x64)

(:callw "empty-8042)
(:movb #xdf :al)
(:outb :al #x60)
(:callw "empty-8042)

;; Poll the floppy"s sectors per track

(:movw 5 (:bp ,+sectors-per-track+))
check-geometry
(:incb (:bp ,+sectors-per-track+))
(:jz "read-error)
(:movw (:bp ,+sectors-per-track+) :cx )
(:movw #x0201 :ax)
(:xorw :dx :dx)
(:movw ,read-buffer-segment :bx)
(:movw :bx :es)
(:xorw :bx :bx)
(:int #x13) ; Call BIOS routine
(:testb :ah :ah)
(:jz "check-geometry)
(:decb (:bp ,+sectors-per-track+))

;;
;; Read sectors into memory
;;

(:movw ,first-sector (:bp ,+linear-sector+))
(:movl ,load-address (:bp ,+destination+))

read-loop

(:cmpw ,last-sector (:bp ,+linear-sector+))
(:jg "read-done)

(:movw "track-start-msg :si) ; Print "(" to screen for each track
(:callw "print)

(:movw (:bp ,+linear-sector+) :ax)
(:movb (:bp ,+sectors-per-track+) :cl)
(:divb :cl :ax) ; al=quotient, ah=remainder of :ax/:cl

(:movb :ah :cl) ; sector - 1
(:movb :al :dh)
(:andb 1 :dh) ; head
(:movb :al :ch)
(:shrb 1 :ch) ; track
(:xorb :dl :dl) ; drive = 0
(:movw (:bp ,+sectors-per-track+) :ax)
(:subb :cl :al) ; number of sectors (rest of track)
(:incb :cl)
(:addw :ax (:bp ,+linear-sector+)) ; update read pointer
(:movw (:bp ,+linear-sector+) :bx) ; subtract some if it"s the last track.
(:subw ,last-sector :bx)
(:jc "subtract-zero-sectors)
(:subw :bx :ax)
(:jz "read-done)
subtract-zero-sectors
(:movb 2 :ah)

(:movw ,read-buffer-segment :bx)
(:movw :bx :es)
(:xorw :bx :bx)
(:int #x13) ; Call BIOS routine

(:jc "read-error)
(:movzxb :al :ecx)

;;
;; Install GS as 4GB segment
;; http://www.faqs.org/faqs/assembly-language/x86/general/part2/
;;
(:cli)
(:lgdt ("gdt-addr)) ; load gdt
(:movcr :cr0 :eax)
(:orb 1 :al)
(:movcr :eax :cr0)
(:jmp (:pc+ 0))
(:movw 16 :bx)
(:movw :bx :gs)
(:andb #xfe :al)
(:movcr :eax :cr0)
(:jmp (:pc+ 0))
(:sti)
;; Completed install GS as 4GB segment.

;; Copy data to destination
(:shll ,(+ 9 -2) :ecx) ; 512/4 = sector-size/word-size
(:movl ,+read-buffer+ :ebx)
(:movl (:bp ,+destination+) :esi)
(:leal (:esi (:ecx 4)) :edx)

(:movl :edx (:bp ,+destination+))

copy-loop
(:decl :ecx)
((:gs-override) :movl (:ebx (:ecx 4)) :edx)
((:gs-override) :movl :edx (:esi (:ecx 4)))
(:jnz "copy-loop)

(:movw "track-end-msg :si) ; Print ")" to screen after each track
(:callw "print)

(:jmp "read-loop)

read-done

motor-loop ; Wait for floppy motor
(:btw 8 (#x43e))
(:jc "motor-loop)

(:movw "entering :si) ; Print welcome message
(:callw "print)

;; Read the cursor position into DH (row) and DL (column).
(:movb 3 :ah)
(:movb 0 :bh)
(:int #x10)

(:cli) ; Disable interrupts
(:lgdt ("gdt-addr)) ; load gdt

(:xorw :ax :ax)
(:movw :ax :es) ; reset es

;;
;; Turn off the cursor
;;

;;; (movb #x01 :ah)
;;; (movw #x0100 :cx)
;;; (int #x10)

;;
;; Load machine status word. This will enable
;; protected mode. The subsequent instruction MUST
;; reload the code segment register with a selector for
;; the protected mode code segment descriptor (see
;; GDT specification).
;;
(:movw 1 :ax)
(:lmsw :ax) ; load word 0 of cr0

;;
;; Do a longjump to new-world. This will cause the CS to
;; be loaded with the correct descriptor, and the processor
;; will now run in 32 bit mode.
;;

(:jmp 8 ("new-world))

;;
;; Display error message and hang
;;
read-error
(:movw "error :si) ; Print error message
(:callw "print)
halt-cpu
(:halt)
(:jmp "halt-cpu) ; Infinite loop

;;
;; Empty the 8042 Keyboard controller
;;
empty-8042
(:callw "delay)
(:inb #x64 :al) ; 8042 status port
(:testb 1 :al) ; if ( no information available )
(:jz "no-output) ; goto no_output
(:callw "delay)
(:inb #x60 :al) ; read it
(:jmp "empty-8042)
no-output
(:testb 2 :al) ; if ( input buffer is full )
(:jnz "empty-8042) ; goto empty_8042
(:ret)

delay
(:xorw :cx :cx)
delay-loop
(:loop "delay-loop)
(:ret)

print ,@(mkasm16-bios-print)

;; Data
welcome (:% :format 8 "Loading Movitz ~D..~%"
,(incf *bootblock-build*))
entering (:% :format 8 "~%Enter..")
error (:% :format 8 "Failed!)")
track-start-msg (:% :format 8 "(")
track-end-msg (:% :format 8 ")")
sector-msg (:% :format 8 "-")

(:% :align 16)
gdt
(:% :bytes 16 0)
gdt-addr
(:% :bytes 16 ,(1- (* 3 8)))
(:% :bytes 32 "gdt) ; both the null and pointer to gdt
;; (% fun (make-segment-descriptor-byte)) ; dummy null descriptor
(:% :fun (make-segment-descriptor-byte :base 0 :limit #xfffff ; 1: code segment
:type 10 :dpl 0
:flags (s p d/b g)))
(:% :fun (make-segment-descriptor-byte :base 0 :limit #xfffff ; 2: data segment
:type 2 :dpl 0
:flags (s p d/b g)))
;; (% align 4)
new-world
;; ..must be concatenated onto here.
)))

(節選自 movitz/bootblock.lisp


看了題主的描述,感覺最多只是寫的像php,哪裡是彙編了?題主公司的KPI裡面肯定對員工code review別人沒有要求,才變成這樣的。趕緊說服老闆加上去。


寫得像彙編…例如這樣?

jkndrkn/mips-lisp

#|

fib.lisp

John David Eriksen
http://www.jkndrkn.com
john.eriksen@yahoo.com

Non-recursive implementation of Fibonacci sequence
computation that deposits the 1st through the 10th
Fibonacci numbers sequentially in memory.

This benchmark exercises branching, alu,
and memory instructions.

|#

;; Setup constants
(addi r1 r0 10) ; array_size
(addi r2 r0 0) ; A[].base_offset

;; Calculate fib(n) where n = [0 .. 9] and store sequentially in A[]
(addi r5 r0 0) ; r5 = i = 0
(label "loop_i")

(addi r3 r0 1) ; r3 = a = 1
(addi r4 r0 0) ; r4 = b = 1
(addi r7 r0 0) ; r7 = result = 0

(addi r6 r0 0) ; r5 = j = 0
(label "loop_j")
(beq r5 "done" r6) ; if (i == j) goto done
(add r7 r3 r4) ; result = a + b
(addi r3 r4 0) ; a = b
(addi r4 r7 0) ; b = result
(addi r6 r6 1) ; j++
(j "loop_j") ; goto loop_b
(label "done")

(add r8 r2 r5) ; r8 = i + A[].base_offset
(sw r7 0 r8) ; A[i] = result

(addi r5 r5 1) ; i++
(bne r5 "loop_i" r1) ; if (i != array_size) goto loop_a

是長得挺像彙編的…


強答一番,下面是我FPGA課的期末大作業,本來要求是用verilog寫個processor,於是……用Haskell寫了個CPU,由clash把Haskell轉成可綜合的verilog代碼燒到FPGA里。

就是這個: 計算機領域有哪些短小精悍的輪子?(僅用於教學)? - 編程 - 知乎

指令集也是Haskell里自定義的數據結構,同樣可以燒到FPGA的ROM里跑

你感受下,函數式語言寫的像彙編是怎樣一種體驗:


感覺在樓主的概念裡面,寫的亂的不容易看懂的都叫彙編。

話說我覺得彙編很好閱讀啊……


彙編:都用上if了,能算像嗎?

我跟題主至多有一個人學的不是假彙編


我學了假的彙編

一覺起來這麼多人就忍不住的去貼了代碼,這是職業病,得治……

.


select...where...from... if...else...end if.


都有if了還彙編……


推薦閱讀:

Mathematica中如何定義f[x+y]=f[x]+f[y]?
如何在Unity中實現MVC模式?
同名的全局變數在循環體中怎麼引用?
請問你們能熟練使用的編程語言有那些?
學編程的時候都會先學進位轉換,請問在實際編程過程中,這些東西有用么?

TAG:編程語言 | 編程 | 吐槽 | 函數式編程 | OCaml |