簡體   English   中英

使用Haskell的類型替換斷言語句或其他語言的檢查

[英]Using Haskell's types to replace assert statements or if checks in other languages

抱歉,如果您的問題很基本,那么我對Haskell還是很陌生。 可以說我有一個只能使用黃金比例(1.618)中的兩個數字的函數,如何定義myfun xy的類型以僅采用黃金比例數字。 如果我從程序中調用沒有黃金分割率數字的myfun會發生什么(編譯錯誤?)? 如果在運行時通過用戶輸入進行無黃金比率編號的呼叫會發生什么情況?

您可能想要只能用黃金比率數字構造的ADT ,然后編寫myfun接受該數據類型。

我以Integer作為基本類型,但您可以使用其他類型(例如:Double或Float),甚至可以是多態的。

1)制作ADT

module Golden (Gold, getGold, buildGold) where

data Gold = G Integer Integer

getGold :: Gold -> (Integer, Integer)
getGold (G x y) = (x, y)

buildGold :: Integer -> Integer -> Maybe Gold
buildGold x y
    | isGolden x y = Just (G x y)
    | otherwise    = Nothing

注意,此模塊導出Gold類型,但不導出構造函數(即,不是G )。 因此,獲取Gold類型值的唯一方法是buildGold ,它執行運行時檢查-但只能執行一次檢查-因此,所有使用者都可以使用Gold的值並將其假定為黃金比率,而無需檢查。

2)使用ADT來建立myfun

myfun :: Gold -> ???
myfun g = expr
  where (x, y) = getGold g

現在,如果您嘗試使用非黃金數字(一個非Gold類型的值)調用myfun ,則會出現編譯時錯誤。

buildGold要構建黃金數字,必須使用buildGold函數,該函數強制檢查數字。

注意什么時候被檢查! 您有一個編譯時保證,始終要為myfun和要與Gold一起使用的所有其他函數提供黃金分割率。 程序輸入(來自用戶,網絡或其他任何地方)仍需要運行時檢查,這就是buildGold提供的功能; 顯然,永遠不會有一個程序可以保證人類不會鍵入不想要的東西。

問題注釋中給出的替代方案也值得考慮。 如果您只需要一個函數myfun ,那么ADT可能會很繁重,否則可能失敗,然后只有myfun :: (Integer, Integer) -> Maybe ???

最簡單的技術是使用智能構造函數 ,該函數使用從Int到GoldenInt的函數,該函數檢查您的值是否在要求的比率內。

花費更多的精力,您可以使用類型級別數字來確保不需要運行時檢查,但是,如果您是初學者,我將堅持使用智能構造函數方法。

湯姆在上面的回答就是這個成語的例子。

實際上,您能做的最好的事情就是運行時檢查。 可能會有一些我不知道的類型級別的演算(請參閱luqui的評論),但這在Haskell中並不實用。

您可以使用assert ,這是您要替換的,

checker :: a -> b -> Bool
checker x y = x * 1.618 `approxEqual` y

unsafeMyfun :: a -> b -> c
unsafeMyfun x y = assert (checker x y) (doRealThingWith a b)

或返回Maybe a (或Either err a )以避免純函數無法捕獲的異常,

myfun :: a -> b -> Maybe c
myfun x y = do
              guard $ checker x y
              return $ doRealThingWith x y

或使用Tom的答案等中的自定義合同類型。無論如何,都不可能在編譯時檢查約束。 實際上,由於IO monad,任何編譯時約束都無法精確確定。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM