我是Haskell的新手,正在做一個Collatz猜想的練習題。要求的輸出是由一個給定的整數到1所需的步驟數。這是我第一次使用Maybe型別,這可能是導致我困惑的原因。
根據我發現的另一個解決相同問題的方案,我有這個作業方案:
collatz :: Integer -> Maybe Integer ->
collatz n
| n <= 0 = Nothing[/span
| n == 1 = Just0
| 偶數 n = fmap succ . collatz $ n `div` 2 *否則 = fmap succ .
| 否則 = fmap succ . collatz $ 3 * n 1
我不清楚的是,為什么在這種情況下有必要使用fmap succ。根據我目前的理解,我希望能夠在遞回呼叫collatz的輸出上呼叫succ,以便將其遞增;然而,這就會產生一個錯誤:
> No instance for (Enum (Maybe Integer)
產生于使用of `succ'。
看起來這個錯誤與在一個Maybe Integer型別而不是Integer上呼叫succ有關。這個錯誤是不是因為Maybe Integer在Haskell中不被認為是可列舉的?如果是這樣的話,為什么呼叫fmap succ可以解決這個問題?
uj5u.com熱心網友回復:
如果你剛開始學習Haskell,使用.和$不必要地給你帶來額外的認知負擔。你所擁有的更簡單的寫法是
collatz :: Integer -> Maybe Integer ->
collatz n
| n <= 0 = Nothing[/span
| n == 1 = Just 0
| 偶數 n = fmap succ (collatz (n `div` 2)
|否則 = fmap succ (collatz (3 * n 1)
現在,什么是succ?如果我們看一下它的型別,
> :t succ
succ :: Enum a => a -> a
主要需要注意的是,輸入和輸出型別是同一個。它也是Enum類的一個實體,這只是說這個型別實作了其特定版本的succ函式(這樣有點回圈)。
因為我們正在處理Integers,它確實實作了它們的succ版本
succ :: Integer -> Integer[/span
succ i = i 1
這一切都很好,并且得到了照顧。
Except collatz :: Integer -> Maybe Integer接收一個Integer并回傳一個Maybe Integer:
--偽代碼。
Maybe Integer = Nothing
| Just Integer = Nothing
-- ^標簽 ^包含的資料型別
所以我們需要將succ應用到包含的Integer。而這就是fmap的作業:
--偽碼
> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
> :t fmap @ Maybe[/span
fmap :: (a -> b) -> Maybe a -> Maybe b
> :t fmap @ Maybe succ @ Integer.
fmap :: Maybe Integer -> Maybe Integer
這是一個由一型別別定義的通用函式,這些型別各自定義了它們的專門版本。正如Maybe所做的那樣:
--偽碼:
fmap f Nothing= Nothing
fmap f (Just i) = Just (f i)。
-- ^^ f應用在 "內部"上
-- ^^當里面有東西時。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/316976.html
標籤:
上一篇:一個類中的多個型別同義詞
