簡體   English   中英

在List的元素上定義約束函數?

[英]Define Function with Constraint on List's Elements?

如何使用以下簽名定義函數,

f :: [Int???] -> [Int]
f xs = _ -- what I do with xs doesn't matter for the question

其中aInt的列表

這樣第一個參數的輸入(即列表元素)必須>= 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.

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