Haskell学习笔记6 - 八道训练题

Q1

type Predicate a = a -> Bool

testP :: Bool 
testP = (isPass [] == False) &&
 (isPass [2, 5, 6, 7] == False) &&
 (isPass [12, 15, 16, 17] == True) &&
 (isPass [5, 8, 12, 15] == True)

isPass :: Predicate [Integer]

写一个函数isPass,如果列表中的和大于40就返回True,否则返回False

isPass = (>=40) . sum
-- 或
isPass ns = sum ns >= 40

这里可以直接用sum实现

>>> sum [1..10]
55

sum函数会返回一个列表的和

Q2

testAl :: Bool
testAl = (isAlphabet "" == True ) &&
 (isAlphabet "hello!" == False) &&
 (isAlphabet "hello" == True) &&
 (isAlphabet "Hello" == True) &&
 (isAlphabet "Wow3" == False) &&
 (isAlphabet "Software" == True)

isAlphabet:: Predicate String

写一个函数isAlphabet,判断是否仅为为英文字母

isAlphabet = all (`elem` (['A'..'Z']++['a'..'z']))

使用all和`elem`,看一下all的解释

>>> all (> 3) [1,2]
False

all后面会跟一个函数和一个列表,如果列表中所有元素都符合函数的条件,就会返回True,否则返回False

>>> 3 `elem` [1,2,3,4,5]
True

elem则是会判断前面输入的值是否存在于后面的列表中

Q3

testcmbList :: Bool  
testcmbList =
    (cmbList ['s'] "comp"  == "cs") &&
    (cmbList "otae""sfwr" == "software") &&
    (cmbList [1, 3, 5] [0, 2, 4, 6]  == [0,1,2,3,4,5]) &&
    (cmbList ["1", "2", "3"]["THE", "WORLD", "HEY"] == 
        ["THE","1","WORLD","2","HEY","3"])     


cmbList :: [a] -> [a] -> [a]

写一个函数cmbList,将两个列表合并成一个列表,并且返回的列表中奇数位置的元素为第一个列表中的值,偶数位置的元素为第二个列表中的值(起始位置为0)

cmbList fs ss = concatMap tup2lst $ zip ss fs
   where 
   tup2lst (x,y) = [x,y]

先把两个列表zip起来,zip的功能如下

>>> zip [1, 2] ['a', 'b']
[(1,'a'),(2,'b')]

会把两个列表中对应位置的元素合并成一个元组,再把所有元组放在一个列表中

tup2lst就是一个自己写的函数,会把元组转换成列表

concatMap会使用tup2lst这个函数,把所有元组先变成列表,然后再整合成一个列表

>>> concatMap (take 3) [[1..], [10..], [100..], [1000..]]
[1,2,3,10,11,12,100,101,102,1000,1001,1002]

以上面zip的例子为例:

[(1,'a'),(2,'b')]
-- tup2lst之后变成
[[1,'a'],[2,'b']]
-- 再concatMap变成
[1,'a',2,'b']

Q4

testcmbProd :: Bool  
testcmbProd =
    (cmbProd [] [5, 6]  == []) &&
    (cmbProd [2, 3, 4] [5, 6]  == [10,18]) &&
    (cmbProd [0.23, 3.4, 7.88, 9.21] [3.4, 5] == [0.782,17.0]) &&
    (cmbProd [0.23, 3.4, 7.88, 2*0.3] [3.4, 1.3, 2.1, 2]  == 
        [0.782,4.42,16.548000000000002,1.2]) 

cmbProd :: Num x => [x] -> [x] -> [x]

实现函数cmbProd,将两个列表的乘积返回成一个列表,返回列表的长度应等于最短列表长度

cmbProd = zipWith (*)

可以直接用zipWith实现

>>> zipWith (+) [1, 2, 3] [4, 5, 6]
[5,7,9]

zipWith就是把函数应用到后面两个列表中,并返回一个列表

Q5

testsqDiff :: Bool 
testsqDiff =
    (sqDiff []               == []) &&
    (sqDiff [4, 6]           == []) &&
    (sqDiff [6, 4]           == [4]) &&
    (sqDiff [4, 6, 3, 1, 8]  == [9, 4])


sqDiff :: [Int] -> [Int]

实现一个函数sqDiff,返回列表中两个连续数字差的平方

必须满足一个条件:前一个数字必须大于后面的数字才会返回

sqDiff    []     = []
sqDiff    (x:xs) = [ (a - b) * (a - b) | (a,b) <- zip (x:xs) xs, a > b ]

第二行表达式的意思是在满足a>b的条件下,使用zip遍历整个列表

最后返回(a - b) * (a - b)

>>> zip [1, 2] ['a', 'b']
[(1,'a'),(2,'b')]

(a,b) <- zip (x:xs) xs,(x:xs)就是从列表的第一个元素开始遍历,对应a

xs从第二个元素开始,对应b

Q6

testM2int :: Bool
testM2int = 
    (maybe2int []        == 0) &&
    (maybe2int [Just 23] == 23) &&
    (maybe2int [Nothing] == 0) &&
    (maybe2int [Just 2, Nothing, Just 3, Just 16, Nothing] == 21)


maybe2int :: [Maybe Int] -> Int 

实现一个函数maybe2int,返回列表的和并且为Int型,Nothing不会影响结果

maybe2int xs = sum [x | (Just x) <- xs]

Q7

testcmb :: Bool
testcmb = (cmb "Hello" [] [] == []) &&
 (cmb "Prod" [2, 3] [] == []) &&
 (cmb "List" [] [2, 3] == []) &&
 (cmb "Prod" [2, 3, 4] [5, 6] == [10,18]) &&
 (cmb "List" [2, 3, 4] [5, 6] == [5,2,6,3]) &&
 (cmb "Haskell" [2, 3, 4] [5, 6] == []) &&
 (cmb "Prod" [2, 3, 4] [5, 6, 7] == [10,18,28]) &&
 (cmb "List" [2, 3, 4] [5, 6, 7] == [5,2,6,3,7,4])


cmb :: Num a => String -> [a] -> [a] -> [a]

实现一个函数cmb

如果输入Prod就会返回两个列表的乘积

如果输入List就会合并两个列表,第一个列表在奇数位置,第二个列表在偶数位置

输入其他则返回空列表

cmb cmd fs ss = concatMap (f cmd) (zip ss fs)
  where
    f "List" (x, y) = [x, y]
    f "Prod" (x, y) = [x * y]
    f _      _      = []

三个元素,cmd fs ss

cmd代表输入的指令,fs和ss则代表两个列表

zip ss fs,把位置调一下,因为列表下标从0开始,所以应该第二个列表在前

f cmd,f是自己实现的函数,如果为List就[x,y],Prod就[x*y]其他就[]

并且把zip中的元组[(),()]改成了列表[[],[]]

concatMap实现完f cmd函数之后,再把[[],[]]大列表中的所有小列表整合成一个列表

Q8

data year1 = Student {name :: String, Chinese, Math, Eng :: Int}

s1Db :: [year1]
s1Db = [Student {name = "Beth", Chinese = 65, Math = 58, Eng = 79},
       Student {name = "Adam", Chinese = 55, Math = 68, Eng = 61},
       Student {name = "Lisa", Chinese = 60, Math = 72, Eng  = 65},
       Student {name = "Will", Chinese = 71, Math = 52, Eng  = 49},
       Student {name = "Mark", Chinese = 67, Math = 78, Eng = 50}]

8a)

test1MK :: Bool
test1MK = c1Mk s1Db == [("Beth",65),("Adam",55),("Lisa",60),
   ("Will",71),("Mark",67)]

c1Mk :: [year1] -> [(String, Int)]

实现一个函数c1MK,返回数据中所有学生的名字和语文成绩

the1Mk ss = [(name s, Chinese s) | s <- ss]

8b)

testMath:: Bool
testMath= tMath s1Db == [("Lisa",65,60),("Mark",50,67)]


tMath :: [year1] -> [(String, Int, Int)]

实现函数tMath,如果学生的Math成绩大于70,返回名字和Eng和Chinese的成绩,Eng在前

tMath ss = [(name s, Eng s, Chinese s) | s <- ss, Math s > 70]

8c)

testavg:: Bool
testavg = avgENG s1Db == 60.8

avgENG :: [year1] -> Float  

返回ENG的平均分

avgENG ss = fromIntegral (sum gList) / fromIntegral (length gList)
    where
      gList = [ENG s | s <- ss]
fromIntegral :: (Integral a, Num b) => a -> b

将任意 Integral 值转为任意数字类型

gList就是对ENG进行遍历,再应用sum函数,得到列表的和

这里使用fromIntegral是因为要把Int值转换为Float

Hoogle

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值