跳轉到內容

另一個 Haskell 教程/語言基礎/解答

來自華夏公益教科書,開放的書籍,開放的世界
Haskell
另一個 Haskell 教程
序言
介紹
入門
語言基礎 (解答)
型別基礎 (解答)
IO (解答)
模組 (解答)
高階語言 (解答)
高階型別 (解答)
單子 (解答)
高階 IO
遞迴
複雜度

它繫結得更緊密;實際上,函式應用比任何其他東西都繫結得更緊密。為了看到這一點,我們可以做一些類似的事情

示例

Prelude> sqrt 3 * 3
5.19615

如果乘法繫結得更緊密,結果將是 3。

對、三元組等等

[編輯 | 編輯原始碼]

解答:snd (fst ((1,'a'),"foo"))。這是因為首先我們要取元組的第一半:(1,'a'),然後從這裡我們要取第二半,只得到'a'

如果你嘗試了fst (snd ((1,'a'),"foo")),你會得到一個型別錯誤。這是因為snd的應用會讓你得到fst "foo"。但是,字串“foo”不是元組,所以你不能將fst應用於它。

簡單列表函式

[編輯 | 編輯原始碼]

解答:map Data.Char.isLower "aBCde"

解答:length (filter Data.Char.isLower "aBCde")

解答:foldr max 0 [5,10,2,8,1]

你也可以使用foldlfoldr的情況更容易解釋:我們將每個cons替換為max的應用,並將空列表替換為 0。因此,最內層的應用將取 0 和列表的最後一個元素(如果存在)的最大值。然後,下一個內層的應用將返回之前最大值和倒數第二個元素的最大值。這將持續下去,將當前的最大值一直帶到列表的開頭。

foldl的情況下,我們可以認為這是按順序檢視列表中的每個元素。我們從“狀態” 0 開始。我們取出第一個元素並檢查它是否大於我們當前的狀態。如果是,我們將當前狀態替換為該數字,然後繼續。這種情況發生在每個元素上,因此最終會返回最大元素。

解答:fst (head (tail [(5,'b'),(1,'c'),(6,'a')]))

原始碼檔案

[編輯 | 編輯原始碼]

let 繫結

[編輯 | 編輯原始碼]

我們可以將斐波那契函式定義為

fib 1 = 1
fib 2 = 1
fib n = fib (n-1) + fib (n-2)

我們也可以使用顯式的if語句,比如

fib n =
  if n == 1 || n == 2
    then 1
    else fib (n-1) + fib (n-2)

兩者都可以接受,但第一個在 Haskell 中可能更自然。

我們可以定義

然後輸入程式碼

mult a 0 = 0
mult a 1 = a
mult a b = 
    if b < 0
        then 0 - mult a (-b)
        else a + mult a (b-1)

請注意, 我們進行遞迴操作並不重要。我們也可以將其定義為:

mult 0 b = 0
mult 1 b = b
mult a b = 
    if a < 0
        then 0 - mult (-a) b
        else b + mult (a-1) b

我們可以將 my_map 定義為

my_map f [] = []
my_map f (x:xs) = f x : my_map f xs

回顧一下,my_map 函式應該將函式 f 應用於列表中的每個元素。在列表為空的情況下,沒有元素可以應用函式,因此我們只返回空列表。

在列表非空的情況下,它是一個元素 x 後跟一個列表 xs。假設我們已經正確地將 my_map 應用於 xs,那麼我們剩下的唯一工作就是將 f 應用於 x,然後將結果組合在一起。這就是第二行所做的。

互動性

[編輯 | 編輯原始碼]

以下程式碼出現在 Numbers.hs 中。唯一棘手的部分是 getNumsshowFactorials 中的遞迴呼叫。

module Main
    where

import System.IO

main = do
  nums <- getNums
  putStrLn ("The sum is " ++ show (sum nums))
  putStrLn ("The product is " ++ show (product nums))
  showFactorials nums

getNums = do
  putStrLn "Give me a number (or 0 to stop):"
  num <- getLine
  if read num == 0
    then return []
    else do rest <- getNums
            return ((read num :: Int):rest)

showFactorials []     = return ()
showFactorials (x:xs) = do
  putStrLn (show x ++ " factorial is " ++
            show (factorial x))
  showFactorials xs

factorial 1 = 1
factorial n = n * factorial (n-1)

getNums 的思路正如提示中所述。對於 showFactorials,我們首先考慮遞迴呼叫。假設我們有一個數字列表,第一個數字是 x。首先,我們打印出顯示階乘的字串。然後,我們打印出剩餘部分,因此進行了遞迴呼叫。但是,在空列表的情況下我們該怎麼辦呢?顯然我們已經完成了,所以我們不需要做任何事情,因此我們只需 return ()

請注意,這必須是 return () 而不是 (),因為如果我們只是寫 showFactorials [] = (),那麼這將不是一個 IO 操作,因為它需要是一個 IO 操作。有關這方面的更多說明,你應該繼續閱讀教程。

華夏公益教科書