Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell SYB:listify结果的映射可以用gfoldl重写吗?_Haskell_Generic Programming_Fold_Scrap Your Boilerplate - Fatal编程技术网

Haskell SYB:listify结果的映射可以用gfoldl重写吗?

Haskell SYB:listify结果的映射可以用gfoldl重写吗?,haskell,generic-programming,fold,scrap-your-boilerplate,Haskell,Generic Programming,Fold,Scrap Your Boilerplate,我可以使用SYB的gfoldl一次完成listify结果的映射吗 例如,考虑以下代码: extractNums :: Expr -> [Int] extractNums e = map numVal $ listify isNum e where isNum :: Expr -> Bool isNum (Num _) = True isNum _ = False numVal :: Expr -> Int

我可以使用SYB的gfoldl一次完成listify结果的映射吗

例如,考虑以下代码:

extractNums :: Expr -> [Int]
extractNums e = map numVal $ listify isNum e

  where isNum :: Expr -> Bool
        isNum (Num _) = True
        isNum _       = False

        numVal :: Expr -> Int
        numVal (Num i) = i
        numVal _       = error "Somehow filter did not work?"
<>我不喜欢NUMVAL函数,我必须考虑EXPR类型的不同数据构造函数,而我只对num构造函数感兴趣。我宁愿将isNum和numVals替换为下面的VAL函数:

    vals :: [Int] -> Expr -> [Int]
    vals xs (Num x) = x : xs
    vals xs _       = xs

这可以用gfoldl完成吗?怎么做?

也许这不是最优雅的方法,但我的尝试如下:

extractNums :: Expr -> [Int]
extractNums e = everything (++) (mkQ [] q) e
   where q (Num n) = [n]
         q _ = []
不过,我预计它的表现将低于标准。也许使用
flip(++)
会更好?我现在看不到

另一方面,我刚刚意识到
listify
是以类似的方式定义的。所以至少不会比你现在的情况更糟


或者,正如下面@Alex所建议的:

import qualified Data.DList as D

extractNums :: Expr -> [Int]
extractNums e = D.toList $ everything (D.append) (mkQ D.empty q) e
   where q (Num n) = D.singleton n
         q _ = D.empty

函数
listify
定义为

-- | Get a list of all entities that meet a predicate
listify :: Typeable r => (r -> Bool) -> GenericQ [r]
listify p = everything (++) ([] `mkQ` (\x -> if p x then [x] else []))
这类似于
过滤器
。我们可以创建一个类似于
mappaye
的替代方案,它将
map
filter
组合为一个:

import Data.Generics
import Data.Generics.Schemes
import Data.Maybe (maybeToList)
import Data.Typeable

listify' :: (Typeable t) => (t -> Maybe r) -> GenericQ [r]
listify' f = everything (++) ([] `mkQ` (maybeToList . f))
那么你的例子可以表示为

numVal :: Expr -> Maybe Int
numVal (Num i) = Just i
numVal _       = Nothing

test :: Expr -> [Int]
test = listify' numVal

您可以使用
Data.Sequence
中的
DList
Seq
之类的内容。它们有O(1)连接,只有一个O(n)转换到列表。@Alex I添加了一个
DList
版本。另外,根据文档,似乎
Seq
的append是对数的。我一定把append的运行时和snoc的运行时搞混了