跳轉到內容

另一個 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 操作,因為它必須是。為了更清楚地說明這一點,你可能應該繼續閱讀教程。

華夏公益教科書