簡體   English   中英

如何在haskell中正確鍵入可選參數

[英]How to properly type optional arguments in haskell

我正在嘗試編寫一個函數,該函數遞歸地確定解決 collat​​z 猜想所需的步驟數量。 我希望函數輸入只是系列的起始輸入編號,並在第一次迭代中添加一個額外的計數器變量。 JS 等效項如下所示:

const collatz = (v, count) => {
  if (!count) return collatz(v,0)
  if (v === 1) return count
  if (v % 2 === 0) return collatz(v/2, count + 1)
  return collatz(v*3+1, count + 1)
}

我的哈斯克爾代碼:

module CollatzConjecture (collatz) where
collatz :: Integer -> Maybe Integer -> Maybe Integer
collatz v () = collatz v 0
collatz 1 count = Just count
collatz v count 
  | even v = collatz (div v 2) next
  | otherwise = collatz (v * 3 + 1) next
  where next = count + 1

但是編譯器抱怨

    • Couldn't match type ‘Maybe Integer’ with ‘Integer’
      Expected type: Maybe Integer
        Actual type: Maybe (Maybe Integer)
    • In the expression: Just count
      In an equation for ‘collatz’: collatz 1 count = Just count
  |
4 | collatz 1 count = Just count
  |                   ^^^^^^^^^^

我的想法有什么錯誤?

不要使用僅用於實現細節的額外參數污染函數的公共 API。 相反,將您的公共 1 參數函數委托給私有 2 參數函數。 如果你想不出更好的名字,像這樣的內部函數通常被命名為go

collatz :: Integer -> Integer
collatz = go 0
  where go count 1 = count
        go count v | even v = next $ div v 2
                   | otherwise = next $ v * 3 + 1
          where next = go $ count + 1

我還做了一些其他改進:

  1. 當你從不返回Nothing時,沒有理由返回一個Maybe Integer
  2. 我交換了參數順序(先count ),使部分應用gonext更方便。
  3. 我沒有將輔助變量next定義為整數,而是將其定義為go的部分應用,因此您的兩種情況只需重復next ,而不是go (...) next

如果您根本不自己進行計數,整個函數也會簡單得多。 我不會立即建議這樣做,因為與您最初的嘗試相比,它相當難以辨認,但有經驗的 Haskeller 會更像這樣寫:

collatz :: Integer -> Int
collatz = length . takeWhile (/= 1) . iterate step
  where step n | even n = n `div` 2
               | otherwise = 3 * n + 1

您認為的錯誤在於, Maybe不是關鍵字,也不是對編譯器的某種暗示。 它是一個類型構造函數。 Maybe Integer是一種具體的、特定的數據類型。 它用於表示可選性的一般概念,但由具體值(這種類型)表示。

Haskell 中的每個值都有一種類型。 它不能是Int() Haskell 的 sum 類型被標記為unions

類型是一種類型——一種類型。 根據Nothing的數據類型定義, Maybe Maybe Int類型的值可以寫為Just i (其中i :: Int ,即i類型為Int )或Nothing

data Maybe a  =  Nothing
              |  Just a 

從概念上講, Maybe IntEither () Int相同——它確實表示可能是Int或沒有()

data Either a b  =  Left a
                 |  Right b

所以Just i就像Right iNothing就像Left ()

但不是i()本身——它們必須用適當的數據構造函數標記,這里是RightLeft

暫無
暫無

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

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