[英]Define Function with Constraint on List's Elements?
如何使用以下簽名定義函數,
f :: [Int???] -> [Int]
f xs = _ -- what I do with xs doesn't matter for the question
其中a
是Int
的列表
這樣第一個參數的輸入(即列表元素)必須>= 0
,而在編譯時<= 5
?
換一種說法,
f [6]
將無法編譯。
怎么樣:
f :: [Int] -> [Int]
f = filter (\x -> x >= 0 && x <= 5)
還是要對類型(相關類型)強制執行邊界?
如果要限制允許的Int
范圍,最好使用智能構造函數 。 在這里看看。 這個想法是您創建自己的數據類型和自己的自定義構造函數:
newtype Range0_5 = Range0_5 { unRange :: Int }
makeRange0_5 :: Int -> Maybe Range0_5
makeRange0_5 x
| x >= 0 && x <= 5 = Just $ Range0_5 x
| otherwise = Nothing
如果您創建了一個聰明的構造函數 ,那么不要將其暴露給模塊的用戶就很重要。 只需不導出Range0_5
構造函數即可完成此操作。
但是,這不是編譯時檢查。 如果您確實需要這樣的功能,則Haskell以外的其他語言可能更合適。
由於范圍很小,因此您也可以創建一個求和類型來表示它:
data Range0_5 = Int0 | Int1 | Int2 | Int3 | Int4 | Int5
如果簽名是
f :: [Int] -> [Int]
(這是問題的原始形式),那么就不可能在編譯時強制執行約束。 這是從Halting問題的標准對角化論點得出的 。
假設編譯器可以檢測到
f[g x]
不應該編譯。 通過將編譯器的源代碼合並到g
,它可以選擇與編譯器決定相反的選項。
在您對Liquid Haskell (似乎是一個非常有趣的項目)發表評論之后,請注意以下幾點:
{-@ type Even = {v:Int | v mod 2 = 0} @-}
{-@ foo :: n:Even -> {v:Bool | (v <=> (n mod 2 == 0))} @-}
foo :: Int -> Bool
foo n = if n^2 - 1 == (n + 1) * (n - 1) then True else foo (n - 1)
LiquidHaskell聲稱此函數不安全,因為可能foo n
調用foo (n - 1)
。 但是請注意,這絕不會發生:它只能被稱為如果關系N 2 - 1≠(N + 1)(N - 1),這可能永遠不會發生。
再次,這不是對LiquidHaskell質量的批評,而是僅僅指出它也不能解決類似問題的停止問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.