如何在Haskell中映射多个参数上的函数列表?
我有三个函数(如何在Haskell中映射多个参数上的函数列表?,haskell,currying,Haskell,Currying,我有三个函数(getRow,getColumn,getBlock),它们有两个参数(x和y),每个参数都生成相同类型的列表。我想写第四个函数来连接它们的输出: outputList :: Int -> Int -> [Maybe Int] outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 该函数可以工作,但是有没有办法将双映射(带有三个“$”的)重写为一个映射 import Dat
getRow
,getColumn
,getBlock
),它们有两个参数(x和y),每个参数都生成相同类型的列表。我想写第四个函数来连接它们的输出:
outputList :: Int -> Int -> [Maybe Int]
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
该函数可以工作,但是有没有办法将双映射(带有三个“$”的)重写为一个映射
import Data.Monoid
outputList :: Int -> Int -> [Maybe Int]
outputList = mconcat [getRow, getColumn, getBlock]
你应该得到一个解释 首先,我要明确指出,所有这些函数都具有相同的类型
outputList, getRow, getColumn, getBlock :: Int -> Int -> [Maybe Int]
现在让我们从你最初的定义开始
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
这些函数产生一个[可能是Int]
,任何东西的列表都是一个幺半群。单向组合列表与串联列表相同,因此我们可以将concat
替换为mconcat
outputList x y = mconcat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
另一个是幺半群的东西是函数,如果它的结果是幺半群的话。也就是说,如果b
是幺半群,那么a->b
也是幺半群。单向组合函数与调用具有相同参数的函数,然后单向组合结果相同
所以我们可以简化为
outputList x = mconcat $ map ($ x) [getRow,getColumn,getBlock]
然后再去
outputList = mconcat [getRow,getColumn,getBlock]
我们完了
虽然在本例中,我不确定它是否增加了。作为第一步,我们观察到您的定义
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
可以使用函数组合运算符()
而不是函数应用程序运算符($)
重写,如下所示
outputList x y = (concat . map ($ y) . map ($ x)) [getRow,getColumn,getBlock]
接下来我们注意到map
是列表中fmap
的另一个名称,并且满足fmap
定律,因此,我们特别有map(f.g)==map f。地图g
。我们应用这条定律,使用map
的单个应用程序定义一个版本
outputList x y = (concat . map (($ y) . ($ x))) [getRow,getColumn,getBlock]
outputList x y = concatMap (($ y) . ($ x)) [getRow,getColumn,getBlock]
最后一步,我们可以用concatMap
替换concat
和map
的组合
outputList x y = (concat . map (($ y) . ($ x))) [getRow,getColumn,getBlock]
outputList x y = concatMap (($ y) . ($ x)) [getRow,getColumn,getBlock]
最后,在我看来,虽然Haskell程序员倾向于使用许多奇特的运算符,但通过
outputList x y = concatMap (\f -> f x y) [getRow,getColumn,getBlock]
正如它清楚地表达的,函数的作用是什么。但是,使用类型类抽象(如另一个答案中所示)可能是一件好事,因为您可能会发现您的问题具有某种抽象结构并获得新的见解。我将使用@dave4420的答案,因为它最简洁,并且准确地表达了您的意思。但是,如果您不想依赖
Data.Monoid
,那么您可以按如下方式重写
原始代码:
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
融合两张地图:
outputList x y = concat . map (($y) . ($x)) [getRow,getColumn,getBlock]
更换concat。地图
与混凝土地图
:
outputList x y = concatMap (($y) . ($x)) [getRow,getColumn,getBlock]
你完成了
编辑:AAAA,这与@Jan Christiansen的答案完全相同。哦,好吧 顺便问一下,关于Haskell的一个问题需要多长时间才能得到回答,有没有什么统计数据?我的印象是,90%的哈斯克尔问题几乎都能立即得到回答。虽然这并不能说明答案的质量,但在我看来,答案的质量也相当高。@Jancristiansen:如果您愿意,可以使用stack exchange数据资源管理器来回答这个问题。我做了一个非常粗略的近似(过滤明显的异常值,忽略自我答案,&c.),典型的(即中值)时间大约是20分钟,直到发布第一个答案。