在Haskell中,如何在不同的Traversable之间进行映射?

问题描述 投票:2回答:2

我们知道,fmap的签名是(a -> b) -> f a -> f b,其中fFunctor

[似乎很自然,应该尽可能地通用,并且要更好地分解代码,一个人可能希望将“事物列表”映射到另一个可能不同的“事物列表”。凭直觉,我不明白为什么它不应该或不可能。

[我正在寻找的是功能gmap,其功能与fmap相同,但是具有该签名gmap :: (a -> b) -> (f a) -> (g b),在这里我允许到达和离开的容器有所不同。

我不确定fgFunctors的一般情况是否有意义,但是Traversable类听起来更像是“事物列表”的概念,假设我对迭代数据最感兴趣。

所以签名应该是gmap :: (Traversable f, Traversable g) => (a -> b) -> (f a) -> (g b)

即使gf的性质不同,它仍然可以从左到右遍历,因此仍然觉得应该可以将f的第k个被访问元素映射到g的第k个被访问元素。

假设我的想法没有错,Haskell中是否有这样的功能?

本质上,我的问题是,您将如何以最简洁明了的方式从Haskell中的类似列表的事物转换为另一种?

haskell traversal functor
2个回答
0
投票

您可以创建自己的类型类,并提供一种从一个函子转换为另一个函子的方法,这是将列表转换为Tree的一种方法的示例,但是您可以使用任何您认为正确的方法来解决您的问题。

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}

class (Functor f, Functor g) => GFunctor f g where
  toG :: f a -> g a
  gmap :: (a -> b) -> (f a) -> (g b)
  gmap fn functor = toG $ fmap fn functor

data Tree a = Leaf | Node (Tree a) a (Tree a) deriving Show

instance Functor Tree where
  fmap f Leaf = Leaf
  fmap f (Node t1 x t2) = Node (fmap f t1) (f x) (fmap f t2)

instance GFunctor [] Tree  where
  toG [] = Leaf 
  toG [x] = Node Leaf x Leaf
  toG (x:xs) = Node (toG $ (takeHalf xs)) x ((toG $ dropHald xs))

takeHalf xs = take ((length xs) `div` 2) xs
dropHald xs = drop ((length xs) `div` 2) xs

res :: Tree Int
res = gmap (+1) [1,2,3,4,5]

输出:

   res
=> Node (Node Leaf 3 (Node Leaf 4 Leaf)) 2 (Node Leaf 5 (Node Leaf 6 Leaf))

-1
投票

我认为您可以通过fmap和自然变换来做到这一点。这是一个使用natural-transformations包的示例,目的只是为了演示这个想法。

我想到的第一个自然转变是safeHead

safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x

使用natural-transformations软件包运行GHCi:

Prelude Control.Natural> t = wrapNT safeHead
Prelude Control.Natural> t # [1..3]
Just 1
Prelude Control.Natural> t # []
Nothing
Prelude Control.Natural> fmap show (t # [1..3])
Just "1"
Prelude Control.Natural> fmap show (t # [])
Nothing

所以,对于自然变换t,像fmap f . (t #)这样的事情会做你想要的吗?

((我在想f是正常函数a -> b。]

© www.soinside.com 2019 - 2024. All rights reserved.