Back
Featured image of post Haskell 学习笔记04 - 字符串

Haskell 学习笔记04 - 字符串

导航页

类型瞥一眼

在 REPL 中,可以使用 :type 'a' 查看 'a' 的类型。

ghci> :type 'a'
'a' :: Char

可见 'a' 的类型即为 Char

ghci> :type "Hello"
"Hello" :: String

"Hello" 的类型即为 String

实质上,String 只是一个类型别名(type alias),它等同于 [Char],亦即 Char 列表。

ghci> :info String
type String :: *
type String = [Char]
    -- Defined in ‘GHC.Base’

打印

可以使用 print 打印很多类型:

ghci> print 14
14
ghci> print 14.2
14.2
ghci> print 'a'
'a'
ghci> print "str"
"str"

putStrLnputStr 只用于打印字符串:

ghci> putStrLn "114514"
114514
ghci> putStr "114514"
114514ghci>

显然的,前者在字符串末尾添加换行符。

拼接

-- concat.hs
myGreeting :: String
myGreeting = "hello" ++ " world!"

hello :: String
hello = "hello"

world :: String
world = "world"

main :: IO ()
main = do
  putStrLn myGreeting
  putStrLn secondGreeting
  where
    secondGreeting = concat [hello, " ", world]
 ghc ./*.hs && ./concat
Linking concat ...
hello world!
hello world

可以使用 :: 标注类型,对于 top-level 声明,这是必要的。

拼接字符串可使用 ++concat

作用域

-- Scope.hs
module Scope where

topLevelFunc :: Integer -> Integer
topLevelFunc x =
  x + woot + topLevelValue
  where woot :: Integer
        woot = 10

topLevelValue :: Integer
topLevelValue = 5

woot 仅在 topLevelFunc 函数体中可以访问。而 topLevelFunctopLevelValue 允许模块内,或导入该模块的作用域使用。wherelet 都引入了本地绑定作用域。

拼接函数的类型

不妨查看 (++)concat 的类型:

-- 接收两个列表,输出为一个列表
(++) :: [a] -> [a] -> [a]
-- 接收一组列表,输出为一个列表
concat :: [[a]] -> [a]
-- 当然如果使用 GHC 7.10 或更高, concat 的类型长这样:
concat :: Foldable t => t [a] -> [a]
-- 目前将 Foldable t => t [a] 看作 [[a]] 即可

这两个函数都能不同的类型,但同一函数中的类型 a 必须一致。这正是 Haskell 的重要特性——多态性(polymorphism)。

"hello" ++ " Chris" -- OK
"hello" ++ [1, 2, 3] -- Error

列表函数

因为 String 是特定类型的列表。因此,对于 String 也可以使用标准的列表函数。

例如,(:) 操作符,亦称 cons:

'c' : "hris" -- "chris"
'P' : ""     -- "P
-- head
head "Snake" -- "S"
-- tail
tail "Snake" -- "nake"
-- take
take 0 "Snake" -- ""
take 1 "Snake" -- "S"
take 3 "Snake" -- "Sna"
take 6 "Snake" -- "Snake"
-- drop
drop 3      "Snake" -- "ke"
drop 114514 "Snake" -- ""
drop 1      "Snake" -- "nake"
-- (++)
"Pine" ++ "apple" -- "Pineapple"
-- !!
"Pineapple" !! 0 -- "P"
"Pineapple" !! 4 -- "a"

请注意,以上函数是不安全的(unsafe)。因为它们不考虑全部情况,并会抛出异常:

ghci> head ""
*** Exception: Prelude.head: empty list
ghci> "0123" !! 5
*** Exception: Prelude.!!: index too large

以上,即为基本的字符串处理。

comments powered by Disqus