你對這個函數的索引有一個封閉的解決方案嗎?如果是這樣,是的,你可以使用Enum
派生來簡化事情。例如,
import Prelude hiding (Either(..))
data Dir = Right
| Front
| Up
| Left
| Back
| Down
deriving (Show, Eq, Ord, Enum)
inv :: Dir -> Dir
inv x = toEnum ((3 + fromEnum x) `mod` 6)
注意,這依賴於構造的訂購!
*Main> inv Left
Right
*Main> inv Right
Left
*Main> inv Back
Front
*Main> inv Up
Down
這非常類C,利用構造函數的順序,並且是非Haskelly。妥協是使用更多類型,定義構造函數和它們的鏡像之間的映射,避免使用算術。
import Prelude hiding (Either(..))
data Dir = A NormalDir
| B MirrorDir
deriving Show
data NormalDir = Right | Front | Up
deriving (Show, Eq, Ord, Enum)
data MirrorDir = Left | Back | Down
deriving (Show, Eq, Ord, Enum)
inv :: Dir -> Dir
inv (A n) = B (toEnum (fromEnum n))
inv (B n) = A (toEnum (fromEnum n))
例如,
*Main> inv (A Right)
B Left
*Main> inv (B Down)
A Up
所以至少我們不必做算術運算。並且類型區分鏡子案件。但是,這是非Haskelly。列舉案例絕對沒問題!其他人將不得不在一些點閱讀你的代碼...
這是更好的。準確捕捉類型中的核心概念(維度和方向)。 – 2011-06-06 02:22:59
有道理。在「Sign」上找到「inv Positive」的反轉要比在所有的「Dir」上找到「inv Right」的反轉要好。因此,乾淨地做一個'反向'的唯一方法是讓你的反轉非常小...... – rcbuchanan 2011-06-06 02:33:55
@ rcb451,你錯過了這一點。 「Sign」具有較少數據構造函數的事實是偶然的(儘管當然有益)。關鍵的觀察結果是,「左」與「右」之間的密切關係應體現在它們的類型中,同樣也反映出(例如)「左」與「頂」的遠距離關係。類型系統可以幫助不變式:更多的類型可以表達更精確的不變量。 – Lambdageek 2011-06-06 22:33:15