2016-05-25 8 views
3

Angesichts einer Liste von Funktionen und einer Liste von Zahlen, ich möchte die erste Funktion auf eine Liste von Zahlen angewendet werden, das Ergebnis dann für die zweite Funktion und bald.Anwenden der Zusammensetzung einer Liste von Funktionen auf jede Nummer einer Liste

wantedFunc [(*2), (+2), (/2)] [1,2,3,4] 
       |  |  | 
       |  |  | 
       V  |  | 
     [2,4,6,8]---|  | 
        |  | 
        V  | 
      [4,6,8,10]---| 
          V 
         [2,3,4,5] -- End result 

Gibt es dafür eine eingebaute Funktion?

+0

Zeigen Sie Ihre besten Versuch so weit. – Jubobs

+0

Ich habe wirklich keine elegante Lösung dafür. Ich nehme jede Funktion und fmap sie eins nach dem anderen. –

+1

Provokative Frage: Was tun Sie, wenn die Funktionen in Ihrer Liste nicht alle vom gleichen Typ sind? Provokative Antwort: Sie tun [dies] (http://stackoverflow.com/a/33058994/1523776) –

Antwort

1

Anwendung direkt Ihre Definition wir

wantedFunc :: [(a -> a)] -> [a] -> [a] 
wantedFunc fs xs = foldl (\ys f -> map f ys) xs fs 

bekommen, aber wir können wir können die Funktion Signatur ändern

foldl (\ys f -> map f ys) xs fs 
foldl (\ys f -> flip map ys f) xs fs -- flip map 
foldl (flip map) xs fs     -- remove lambda 
flip (foldl (flip map)) fs xs   -- flip foldl 
flip (foldl (flip map))     -- remove lambda 
flip $ foldl $ flip map     -- or using ($) 

und schließlich

wantedFunc :: [(a -> a)] -> [a] -> [a] 
wantedFunc = flip $ foldl $ flip map 

auf der anderen Seite verwandeln Argumen umdrehen ts und die Listenreihenfolge der Funktionen, und wir können diese Funktion als

wantedFunc' :: [a] -> [(a -> a)] -> [a] 
wantedFunc' = foldr map 

z.B.

main = do 
    print $ wantedFunc [(*2), (+2), (/2)] [1,2,3,4] 
    print $ wantedFunc' [1,2,3,4] [(/2), (+2), (*2)] 

mit Ausgang

[2.0,3.0,4.0,5.0] 
[2.0,3.0,4.0,5.0] 
+0

Das ist ordentlich. Ich drehe die Argumente um. –

3

So etwas wie

import Control.Arrow ((>>>)) 

wantedFunc :: Foldable t => t (a -> a) -> [a] -> [a] 
wantedFunc fs = map f 
    where 
    f = compose fs 
    compose = foldr (>>>) id 

funktioniert der Trick:

λ> wantedFunc [(*2), (+2), (/2)] [1, 2, 3, 4] 
[2.0,3.0,4.0,5.0] 
+3

Oder 'flip (foldl $ Flip-Map)' – josejuan

+0

@josejuan, endete ich mit Ihrer Antwort. Kannst du es als Antwort posten, damit ich es annehmen kann? –

2

Eine rechte fache Lösung wäre:

fun :: (Functor f, Foldable t) => t (a -> a) -> f a -> f a 
fun = foldr (\f -> (. fmap f)) id 

dann,

\> fun [(*2), (+2)] [1,2,3,4] 
[4,6,8,10] 

\> fun [(*2), (+2), (`div` 2)] [1,2,3,4] 
[2,3,4,5] 
1

Hier ist ein fmap fmap Ansatz, mit einem Monoid, um die Funktionen zu komponieren.

newtype Endo a = Endo { unwrap :: a -> a } 

instance Monoid (Endo a) where 
    mempty = Endo id 
    mappend (Endo f) (Endo g) = Endo (g . f) 

wantedFunc = unwrap . mconcat . fmap (Endo . fmap) 

λ wantedFunc [(*2), (+2), (/2)] [1,2,3,4] 
[2.0,3.0,4.0,5.0] 
1

a kann Einzeiler Lösung

sein
> map (foldr (.) id $ reverse [(*2),(+2),(/2)]) [1..4] 
[2.0,3.0,4.0,5.0] 
1

einfach komponieren alle Funktionen und anwenden Karte.

wantedFunc :: [a->a] -> [a] -> [a] 
wantedFunc fs = map (foldl1 (.) fs)