2017-04-22 43 views
3

我對SBCL的適用性最感興趣,但也對Common Lisp的其他實現感到好奇。我們的type hierarchy在常見的lisp中,返回兩個對象最具體的超類型的函數是什麼?

我想要一個函數,給定兩個對象作爲參數,返回符號表示適用於這兩個對象的最具體的超類型。它的使用看起來是這樣的:

(most-specific-super-type x y) 

因此,舉例來說,短浮子和長期浮動的兩個子類型的超類型float的。

如果比較長浮點數和整數,最具體的超級類型是real

如果比較一個複數和一個浮點數,最具體的超級類型是number

比較該類型層次結構中單獨樹中的兩個對象,如果對象不是cons,我們可能會返回類型T或可能​​。

我很想避免自己寫這個,我的直覺告訴我,它看起來像已經寫好的那種功能。

我主要對標準語言中已定義的類型感興趣,但是我的直覺也告訴我必須有一個與CLOS類相關的函數,以確定類的優先級。

所以,如果有,這將是適用於類和類型兩者共同的功能,這將是超好,但我會很高興,如果有隻是類型的解決方案......

+0

我不知道一個準備的使用f但是在https://www.informatimago.com/articles/cl-types/找到了圖表(和源代碼)很有幫助。 –

+0

不要寫'原子。引號運算符不是符號或名稱的一部分。 –

+0

@RainerJoswig:謝謝Rainer,不確定在文本問題的上下文中將符號的格式設置爲不同於文本/字符串的最佳方式:) – DJMelksham

回答

1

當我想到這對其他人來說是值得的,而且我在經過大量搜索之後,無法在任何地方找到這樣的解決方案,而且我沒有得到太多的叮咬,我一直在鞭打基本未被優化的邏輯自己解決方案。

這不是一個最終的工作版本,但應該讓任何其他人尋找相同的問題解決方案,在這一點上,他們可以硬化和重構。請評論並提供任何更正/修復/問題。

感謝@Martin Buchmann發佈https://www.informatimago.com/articles/cl-types/,這是我開始使用的。

第1步:設置散列表。

(defvar *type-hash* (make-hash-table)) 

步驟2:定義有效的類型謂詞的功能。在SBCL上,*對於有效的類型說明符返回TRUE ...因此,我們只是排除該特定的情況並使用處理程序案例來停止程序在非有效的類型指示符上引發條件。

(defun valid-type-p (type-designator) 
    (handler-case (and (SB-EXT:VALID-TYPE-SPECIFIER-P type-designator) 
        (not (eq type-designator 'cl:*))))) 

步驟3:我們提取從:cl包,這是說,口齒不清語言基本上共同的外部符號。我們使用我們的valid-type-p謂詞來測試每個符號。如果其有效,我們將其推送到我們的集合types

注意::cl不是唯一可以做到這一點的軟件包。如果你在你自己的創作包中使用外部cl符號,並且定義了一些你自己導出的自定義CLOS類,我想這也會捕獲其中包含的類層次結構。我沒有太多測試,所以玩了一下。在我的例子中,我避免了這一點,因爲我相信CLOS層次結構和類可以在運行時更改,這可能會導致層次結構無效,除非每次都重新計算它,而我相當確信內部類型是對我而言目前最有用的那些,並且不會改變。

使用每個有效類型作爲鍵,並使用嵌套循環,在此操作之後,散列中的每個鍵現在會給我們一個關鍵字是有效子類型的類型列表。

(let ((types nil)) 
    (do-external-symbols (s :cl) 
    (when (ignore-errors (valid-type-p s)) 
     (push s types))) 

    (loop for type1 in types 
    do (loop for type2 in types 
      do (if (subtypep type1 type2) 
        (push type2 (gethash type1 *type-hash*)))))) 

第4步:我們定義一個函數來給我們最具體的超強型兩種類型。這是如何運作的?

首先,我們得到使用我們新填充的散列獲得的超類型的intersection

其次,我們使用subtypep作爲排序謂詞對路口進行排序。對我來說,使用subtypep當然不是一個直觀的排序謂詞,直到我意識到使用它來排序層次結構是有意義的。我仍然不是100%肯定有沒有一些邊緣情況,但:\

無論如何,我們將返回一個列表的低排名類型的超類型在第一個位置,並得到它,我們乾脆把car

(defun supertype-of-types (type1 type2) 
    (car 
    (sort 
    (intersection (gethash type1 *type-hash*) 
        (gethash type2 *type-hash*)) 
    #'subtypep))) 

步驟5:超型的類型已經是一個有用的功能,但最終我們要在實際值,而不是僅僅代表類型手動輸入符號使用。

功能type-of似乎在SBCL中返回相對特定類型的值,但實際上它可以返回列表。因此,我們需要編寫一個快速的函數提取表示從列表中的第一部分類型的符號,如果這種情況發生......

(defun type-of-object (x) 
    (let ((type (type-of x))) 
    (if (listp type) 
     (car type) 
     type))) 

步驟6:最後,我們寫所需的功能。我們首先明確檢查兩個對象中的一個是否是另一個對象類型的子類型。如果是,那是最具體的超類型。我們這樣做的部分原因是SBCL返回的對象類型比typeof詢問對象時僅由類型符號表示的類型更具體。對於我的優化目的,如果可能的話,我希望能夠使用這些更具體的類型規範,並且這是一個快速的混合,在我明確地找出擴展類型說明符之前獲取其中的一些。如果我沒有放入,我們的下一個技巧返回'INTEGER作爲459和-345最具體的超類型,因爲SBCL返回(INTEGER 0 4611686018427387903)的類型爲459和fixnum,類型爲-345,類型將返回爲INTEGER,而它們實際上都是特定類型fixnum。無論如何,如果一個值的類型不是另一個值類型的子類型,我們使用我們在步驟5中創建的super-type-of-types函數,並且我們總是可以返回T作爲最差情況,因爲所有東西都是子類型型T.

(defun most-specialised-supertype (x y) 
    (let ((typex (type-of x)) 
     (typey (type-of y))) 
    (cond ((subtypep typex typey) typey) 
      ((subtypep typey typex) typex) 
      ((supertype-of-types (type-of-object x) (type-of-object y))) 
      (t t)))) 

和它進行一些測試紡:

(most-specialised-supertype 5.0l0 435789) 
REAL 

(most-specialised-supertype 1.0s0 1.0l0) 
FLOAT 

(most-specialised-supertype 1.0 #c(1 1)) 
NUMBER 

(most-specialised-supertype 'symbol "string") 
ATOM 

(most-specialised-supertype #(1 2 3) #*101) 
VECTOR 

我相信它至少看起來它有點工作:)

相關問題