3

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 関数では、Num コンストラクターだけに関心があるのに、Expr 型のさまざまなデータ コンストラクターを考慮しなければならないのが好きではありません。isNum と numVals を以下の vals 関数のようなものに置き換えます。

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

これは gfoldl で実行できますか? どのように?

4

2 に答える 2

2

関数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 []))

に似ていfilterます。mapMaybe組み合わせmapに似た代替案を作成し、filter必要なものを 1 つにすることができます。

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
于 2015-03-27T13:00:17.580 に答える