【问题标题】:Is there something like `map2 :: (i -> a) -> (i -> b) -> [i] -> [(a,b)]`?有没有类似`map2 :: (i -> a) -> (i -> b) -> [i] -> [(a,b)]`的东西?
【发布时间】:2013-06-14 01:42:29
【问题描述】:

我只是将这样的函数写到map4 只是因为它们看起来很有用:

map2 :: Functor f => (i -> a) -> (i -> b) -> f i -> f (a,b)
map2 f1 f2 = fmap $ \i -> (f1 i, f2 i)

在我继续map8 之前,我想我会问在某些标准模块中是否有类似的东西。 Hayoo 似乎不知道任何具有上述签名的函数。

注意:我已经找到了Control.Arrow.&&&,这将上述内容简化为:

map2 f1 f2 = fmap (f1 &&& f2)

但是对于多于两个的扇出似乎没有类似的功能。

【问题讨论】:

    标签: haskell arrows


    【解决方案1】:

    (->) i 是一个应用函子,所以你可以把(&&&) 写成

    f &&& g = (,) <$> f <*> g
    

    你可以把map3写成

    map3 f1 f2 f3 = map ((,,) <$> f1 <*> f2 <*> f3)
    

    除了它不短于

    map3 f1 f2 f3 = map $ \i -> (f1 i, f2 i, f3 i)
    

    但多亏了 Gabriel 的提示,这个 更短了:

    map3 f1 f2 f3 = map (liftA3 (,,) f1 f2 f3)
    

    【讨论】:

    • 你也可以使用liftA3 (,,)
    • 哦,太好了!那肯定更好(在写作较少的意义上)。
    • 哦...但是liftAn 只定义到n = 3。现在拥有 Idris 的应用语法糖会很好。
    • @Florian 你可以使用 SHE:personal.cis.strath.ac.uk/conor.mcbride/pub/she
    • @SjoerdVisscher 的描述让我发笑......但我更喜欢我的 Haskell 干净而刻薄:)
    【解决方案2】:

    没有超过两个扇出的标准函数,尽管您可以使用嵌套元组来模拟它:

    f :: i -> a
    g :: i -> b
    h :: i -> c
    
    f &&& g :: i -> (a, b)
    
    (f &&& g) &&& h :: i -> ((a, b), c)
    

    如果你不喜欢嵌套元组,那么你将不得不自己编写这个函数:

    fanout3 :: (i -> a) -> (i -> b) -> (i -> c) -> i -> (a, b, c)
    fanout3 f g h i = (f i, g i, h i)
    

    就像你在问题中提到的那样,一旦你有了这样的功能,你就可以map它:

    map (fanout3 f g h) :: [i] -> [(a, b, c)]
    

    【讨论】:

    • 顺便说一句 ... 有没有类似 Flatten 的类型类可以将 (a,(b,c)) 转换为 (a, b, c)[[[a],a],a][a,a,a]。我知道concat,但那里似乎有一个共同的结构。
    • @Florian 我不知道Flatten 类型类,但即使有我也可能会避免它。很难推断它何时会停止扁平化或最终类型会是什么。
    • 我想列出一些 concat 的递归应用程序,直到结果不再改变为止。 (这不就是fix 的意思吗?)
    • @Florian fix 不起作用,因为每次应用 concat 后类型都会发生变化。但是,我通常会避免这样做,因为它不是非常惯用的 Haskell。此外,这需要大量滥用类型类并导致非常混乱的编译器错误。
    • 是的...我不是有意使用它...这只是出于兴趣:)
    猜你喜欢
    • 2021-04-09
    • 2023-03-09
    • 2021-11-01
    • 1970-01-01
    • 2014-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    相关资源
    最近更新 更多