Haskell - 难以理解一小段代码
Haskell - Having trouble understanding a small bit of code
我正在做一项学校任务,我得到了一些示例代码,以后可以使用。我理解这段代码的 90%,但有一小部分 line/function 我一辈子都弄不明白它的作用(顺便说一句,我对 Haskell 很陌生)。
示例代码:
data Profile = Profile {matrix::[[(Char,Int)]], moleType::SeqType, nrOfSeqs::Int, nm::String} deriving (Show)
nucleotides = "ACGT"
aminoacids = sort "ARNDCEQGHILKMFPSTWYVX"
makeProfileMatrix :: [MolSeq] -> [[(Char, Int)]]
makeProfileMatrix [] = error "Empty sequence list"
makeProfileMatrix sl = res
where
t = seqType (head sl)
defaults =
if (t == DNA) then
zip nucleotides (replicate (length nucleotides) 0) -- Row 1
else
zip aminoacids (replicate (length aminoacids) 0) -- Row 2
strs = map seqSequence sl -- Row 3
tmp1 = map (map (\x -> ((head x), (length x))) . group . sort)
(transpose strs) -- Row 4
equalFst a b = (fst a) == (fst b)
res = map sort (map (\l -> unionBy equalFst l defaults) tmp1)
{-Row 1: 'replicate' creates a list of zeros that is equal to the length of the 'nucleotides' string.
This list is then 'zipped' (combines each element in each list into pairs/tuples) with the nucleotides-}
{-Row 2: 'replicate' creates a list of zeros that is equal to the length of the 'aminoacids' string.
This list is then 'zipped' (combines each element in each list into pairs/tuples) with the aminoacids-}
{-Row 3: The function 'seqSequence' is applied to each element in the 'sl' list and then returns a new altered list.
In other words 'strs' becomes a list that contains the all the sequences in 'sl' (sl contains MolSeq objects, not strings)-}
{-Row 4: (transpose strs) creates a list that has each 'column' of sequences as a element (the first element is made up of each first element in each sequence etc.).
--}
我已经为代码中每个标记的行写了一个解释(我认为到目前为止是正确的)但是当我试图弄清楚第 4 行的作用时我卡住了。我了解 'transpose' 位,但我完全无法弄清楚内部 map 函数的作用。据我所知,'map' 函数需要一个列表作为第二个参数才能运行,但内部 map 函数只有一个匿名函数,但没有要操作的列表。非常清楚,我不明白整个内线 map (\x -> ((head x), (length x))) . group . sort
的作用。请帮忙!
奖金!:
这是我无法理解的另一段示例代码(从未在 Haskell 中使用 类):
class Evol object where
name :: object -> String
distance :: object -> object -> Double
distanceMatrix :: [object] -> [(String, String, Double)]
addRow :: [object] -> Int -> [(String, String, Double)]
distanceMatrix [] = []
distanceMatrix object =
addRow object 0 ++ distanceMatrix (tail object)
addRow object num -- Adds row to distance matrix
| num < length object = (name a, name b, distance a b) : addRow object (num + 1)
| otherwise = []
where
a = head object
b = object !! num
-- Determines the name and distance of an instance of "Evol" if the instance is a "MolSeq".
instance Evol MolSeq where
name = seqName
distance = seqDistance
-- Determines the name and distance of an instance of "Evol" if the instance is a "Profile".
instance Evol Profile where
name = profileName
distance = profileDistance
特别是这部分:
addRow object num -- Adds row to distance matrix
| num < length object = (name a, name b, distance a b) : addRow object (num + 1)
| otherwise = []
where
a = head object
b = object !! num
如果你不想解释这个,你不必解释我只是对 'addRow' 实际尝试做的事情(详细)有点困惑。
谢谢!
the inner map function only has an anonymous function but no list to operate on
假设有一个类型为 a -> b -> c
的函数 f
,它有两个参数并且 return 有一个类型为 c
的值。如果使用一个参数调用 f
,它 return 是另一个 b -> c
类型的函数,它将再接受一个参数和 return 一个值。这称为柯里化。
这一行:
map (map (\x -> ((head x), (length x))) . group . sort) (transpose strs)
可以转化为:
map (\str -> (map (\x -> ((head x), (length x))) . group . sort) str)(transpose strs)
在这个表格中,它可能会被清除,实际上有一个列表可以操作。
这个函数
(map (\x -> ((head x), (length x))) . group . sort)
只是sort
、group
和map (\x -> ((head x), (length x)))
的组合。
让我们看看它在 [2,1,1,1,4]
:
上是如何工作的
sort [2, 1, 1, 1, 4]
=> [1, 1, 1, 2, 4]
group [1, 1, 1, 2, 4]
=> [[1,1,1],[2],[4]]
map (\x -> ((head x), (length x)))
=> [(1,3),(2,1),(4,1)]
它只是 return 一个元组列表。每个元组包含一个元素作为第一个元素,出现次数作为第二个元素。
map (\x -> (head x, length x)) . group . sort
是一种生成直方图的惯用方法。当你看到像这样你不理解的东西时,试着把它分解成更小的部分并在样本输入上测试它们:
(\x -> (head x, length x)) "AAAA"
-- ('A', 4)
(group . sort) "CABABA"
-- ["AAA", "BB", "C"]
(map (\x -> (head x, length x)) . group . sort) "CABABA"
map (\x -> (head x, length x)) (group (sort "CABABA"))
-- [('A', 3), ('B', 2), ('C', 1)]
它以 point-free 风格编写,由 3 个函数 map (…)
、group
和 sort
组成,但可以也可以写成 lambda:
\row -> map (…) (group (sort row))
对于转置矩阵中的每一行,它都会生成该行数据的直方图。您可以通过格式化并打印出来获得更直观的表示:
let
showHistogramRow row = concat
[ show $ head row
, ":\t"
, replicate (length row) '#'
]
input = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
putStr
$ unlines
$ map showHistogramRow
$ group
$ sort input
-- 1: ##
-- 2: #
-- 3: ##
-- 4: #
-- 5: ###
-- 6: #
-- 9: #
至于这个:
addRow object num -- Adds row to distance matrix
| num < length object = (name a, name b, distance a b) : addRow object (num + 1)
| otherwise = []
where
a = head object
b = object !! num
addRow
列出从 object
中的第一个元素到其他每个元素的距离。当更简单和更惯用的 map
就足够时,它以一种不明显的方式使用索引到列表中:
addRow object = map (\ b -> (name a, name b, distance a b)) object
where a = head object
通常最好避免 部分 函数,例如 head
,因为它们可能会在某些输入上抛出异常(例如 head []
)。不过,这里没问题,因为如果输入列表为空,则永远不会使用 a
,因此永远不会调用 head
。
distanceMatrix
也可以用 map
表示,因为它只是在列表的所有 tails
上调用一个函数 (addRow
) 并将它们连接起来连同 ++
:
distanceMatrix object = concatMap addRow (tails object)
这也可以写成无点风格。 \x -> f (g x)
可以写成 f . g
;这里,f
是 concatMap addRow
而 g
是 tails
:
distanceMatrix = concatMap addRow . tails
Evol
只是描述了可以生成 distanceMatrix
的类型集,包括 MolSeq
和 Profile
。请注意 addRow
和 distanceMatrix
不需要成为此 class 的成员,因为它们完全根据 name
和 distance
实现,所以您可以将它们移至顶层:
distanceMatrix :: (Evol object) => [object] -> [(String, String, Double)]
distanceMatrix = concatMap addRow . tails
addRow :: (Evol object) => [object] -> Int -> [(String, String, Double)]
addRow object = map (\ b -> (name a, name b, distance a b)) object
where a = head object
我正在做一项学校任务,我得到了一些示例代码,以后可以使用。我理解这段代码的 90%,但有一小部分 line/function 我一辈子都弄不明白它的作用(顺便说一句,我对 Haskell 很陌生)。
示例代码:
data Profile = Profile {matrix::[[(Char,Int)]], moleType::SeqType, nrOfSeqs::Int, nm::String} deriving (Show)
nucleotides = "ACGT"
aminoacids = sort "ARNDCEQGHILKMFPSTWYVX"
makeProfileMatrix :: [MolSeq] -> [[(Char, Int)]]
makeProfileMatrix [] = error "Empty sequence list"
makeProfileMatrix sl = res
where
t = seqType (head sl)
defaults =
if (t == DNA) then
zip nucleotides (replicate (length nucleotides) 0) -- Row 1
else
zip aminoacids (replicate (length aminoacids) 0) -- Row 2
strs = map seqSequence sl -- Row 3
tmp1 = map (map (\x -> ((head x), (length x))) . group . sort)
(transpose strs) -- Row 4
equalFst a b = (fst a) == (fst b)
res = map sort (map (\l -> unionBy equalFst l defaults) tmp1)
{-Row 1: 'replicate' creates a list of zeros that is equal to the length of the 'nucleotides' string.
This list is then 'zipped' (combines each element in each list into pairs/tuples) with the nucleotides-}
{-Row 2: 'replicate' creates a list of zeros that is equal to the length of the 'aminoacids' string.
This list is then 'zipped' (combines each element in each list into pairs/tuples) with the aminoacids-}
{-Row 3: The function 'seqSequence' is applied to each element in the 'sl' list and then returns a new altered list.
In other words 'strs' becomes a list that contains the all the sequences in 'sl' (sl contains MolSeq objects, not strings)-}
{-Row 4: (transpose strs) creates a list that has each 'column' of sequences as a element (the first element is made up of each first element in each sequence etc.).
--}
我已经为代码中每个标记的行写了一个解释(我认为到目前为止是正确的)但是当我试图弄清楚第 4 行的作用时我卡住了。我了解 'transpose' 位,但我完全无法弄清楚内部 map 函数的作用。据我所知,'map' 函数需要一个列表作为第二个参数才能运行,但内部 map 函数只有一个匿名函数,但没有要操作的列表。非常清楚,我不明白整个内线 map (\x -> ((head x), (length x))) . group . sort
的作用。请帮忙!
奖金!:
这是我无法理解的另一段示例代码(从未在 Haskell 中使用 类):
class Evol object where
name :: object -> String
distance :: object -> object -> Double
distanceMatrix :: [object] -> [(String, String, Double)]
addRow :: [object] -> Int -> [(String, String, Double)]
distanceMatrix [] = []
distanceMatrix object =
addRow object 0 ++ distanceMatrix (tail object)
addRow object num -- Adds row to distance matrix
| num < length object = (name a, name b, distance a b) : addRow object (num + 1)
| otherwise = []
where
a = head object
b = object !! num
-- Determines the name and distance of an instance of "Evol" if the instance is a "MolSeq".
instance Evol MolSeq where
name = seqName
distance = seqDistance
-- Determines the name and distance of an instance of "Evol" if the instance is a "Profile".
instance Evol Profile where
name = profileName
distance = profileDistance
特别是这部分:
addRow object num -- Adds row to distance matrix
| num < length object = (name a, name b, distance a b) : addRow object (num + 1)
| otherwise = []
where
a = head object
b = object !! num
如果你不想解释这个,你不必解释我只是对 'addRow' 实际尝试做的事情(详细)有点困惑。
谢谢!
the inner map function only has an anonymous function but no list to operate on
假设有一个类型为 a -> b -> c
的函数 f
,它有两个参数并且 return 有一个类型为 c
的值。如果使用一个参数调用 f
,它 return 是另一个 b -> c
类型的函数,它将再接受一个参数和 return 一个值。这称为柯里化。
这一行:
map (map (\x -> ((head x), (length x))) . group . sort) (transpose strs)
可以转化为:
map (\str -> (map (\x -> ((head x), (length x))) . group . sort) str)(transpose strs)
在这个表格中,它可能会被清除,实际上有一个列表可以操作。
这个函数
(map (\x -> ((head x), (length x))) . group . sort)
只是sort
、group
和map (\x -> ((head x), (length x)))
的组合。
让我们看看它在 [2,1,1,1,4]
:
sort [2, 1, 1, 1, 4]
=> [1, 1, 1, 2, 4]
group [1, 1, 1, 2, 4]
=> [[1,1,1],[2],[4]]
map (\x -> ((head x), (length x)))
=> [(1,3),(2,1),(4,1)]
它只是 return 一个元组列表。每个元组包含一个元素作为第一个元素,出现次数作为第二个元素。
map (\x -> (head x, length x)) . group . sort
是一种生成直方图的惯用方法。当你看到像这样你不理解的东西时,试着把它分解成更小的部分并在样本输入上测试它们:
(\x -> (head x, length x)) "AAAA"
-- ('A', 4)
(group . sort) "CABABA"
-- ["AAA", "BB", "C"]
(map (\x -> (head x, length x)) . group . sort) "CABABA"
map (\x -> (head x, length x)) (group (sort "CABABA"))
-- [('A', 3), ('B', 2), ('C', 1)]
它以 point-free 风格编写,由 3 个函数 map (…)
、group
和 sort
组成,但可以也可以写成 lambda:
\row -> map (…) (group (sort row))
对于转置矩阵中的每一行,它都会生成该行数据的直方图。您可以通过格式化并打印出来获得更直观的表示:
let
showHistogramRow row = concat
[ show $ head row
, ":\t"
, replicate (length row) '#'
]
input = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
putStr
$ unlines
$ map showHistogramRow
$ group
$ sort input
-- 1: ##
-- 2: #
-- 3: ##
-- 4: #
-- 5: ###
-- 6: #
-- 9: #
至于这个:
addRow object num -- Adds row to distance matrix
| num < length object = (name a, name b, distance a b) : addRow object (num + 1)
| otherwise = []
where
a = head object
b = object !! num
addRow
列出从 object
中的第一个元素到其他每个元素的距离。当更简单和更惯用的 map
就足够时,它以一种不明显的方式使用索引到列表中:
addRow object = map (\ b -> (name a, name b, distance a b)) object
where a = head object
通常最好避免 部分 函数,例如 head
,因为它们可能会在某些输入上抛出异常(例如 head []
)。不过,这里没问题,因为如果输入列表为空,则永远不会使用 a
,因此永远不会调用 head
。
distanceMatrix
也可以用 map
表示,因为它只是在列表的所有 tails
上调用一个函数 (addRow
) 并将它们连接起来连同 ++
:
distanceMatrix object = concatMap addRow (tails object)
这也可以写成无点风格。 \x -> f (g x)
可以写成 f . g
;这里,f
是 concatMap addRow
而 g
是 tails
:
distanceMatrix = concatMap addRow . tails
Evol
只是描述了可以生成 distanceMatrix
的类型集,包括 MolSeq
和 Profile
。请注意 addRow
和 distanceMatrix
不需要成为此 class 的成员,因为它们完全根据 name
和 distance
实现,所以您可以将它们移至顶层:
distanceMatrix :: (Evol object) => [object] -> [(String, String, Double)]
distanceMatrix = concatMap addRow . tails
addRow :: (Evol object) => [object] -> Int -> [(String, String, Double)]
addRow object = map (\ b -> (name a, name b, distance a b)) object
where a = head object