2016-10-27 1 views
5

Ich habe eine dieser drei FunktionenGibt es eine vordefinierte Möglichkeit, Berechnungen zu überspringen, die zu Nichts führen?

a :: Int -> Maybe Int 
a i = if i < 100 then Just i else Nothing 

b :: Int -> Maybe Int 
b i = if i < 50 then Just i else Nothing 

c :: Int -> Maybe Int 
c i = if i > 0 then Just i else Nothing 

Und ich möchte, dass sie die Kette zusammen, so dass, wenn das Ergebnis einer Funktion führt zu einer Nothing die Eingabe dieser Funktion stattdessen zurückgegeben.

Ich kann dies mit dieser Funktion erreichen:

import Data.Maybe (fromMaybe) 

e :: Int -> [Int -> Maybe Int] -> Int 
e i [] = i 
e i (f:fs) = e (fromMaybe i $ f i) fs 

-

*Main> e 75 [a,b,c] 
75 

Gibt es eine vorhandene Funktion, Monad eine Instanz oder eine andere Art und Weise in den Basisbibliotheken, die dieses Verhalten zeigt?

+0

Es sollte klar sein, dass Sie dies in der Regel nicht tun können, weil die Ein- und Ausgangstypen variieren. Du kannst eine Funktion vom Typ '(a -> Vielleicht a) -> a -> a' schreiben, aber nicht' (a -> Vielleicht b) -> a -> b' –

+3

Ich würde zuerst '[Int -> Vielleicht Int] 'in' [Int -> Int] 'mit' fromMaybe' wie du es getan hast. Danach würde ich die Liste der Endos zusammenstellen. – chi

+1

'foldr1 (> =>) [a, b, c]' –

Antwort

4

Erweitern meines Kommentars oben - dieser Ansatz unterscheidet sich nicht zu sehr von dem Code, der vom OP gepostet wurde.

Zuerst definieren wir, wie man eine Funktion a -> Maybe a in a -> a umwandelt und den Eingang für Nothing ersetzt.

totalize :: (a -> Maybe a) -> (a -> a) 
totalize f x = fromMaybe x (f x) 

Dann nutzen wir die oben: wir jede Funktion „total“ (im Sinne von no- Nothing s) machen, wickeln Sie es als Endo, dann wir die Liste der Endomorphismen komponieren (mconcat ist Zusammensetzung in der Endo Monoid).

e :: [a -> Maybe a] -> a -> a 
e = appEndo . mconcat . map (Endo . totalize) 

oder sogar (wie unten vorgeschlagen)

e :: Foldable t => t (a -> Maybe a) -> a -> a 
e = appEndo . foldMap (Endo . totalize) 
+2

'e = appEndo. foldMap (Endo. totalize) '? – user3237465

+0

Sie können es auch ohne die 'Endo'-Abstraktion machen: 'compose = foldr (.) Id; e = komponieren. Karte totalize'. –

0

Suchst du nach der vielleicht Monade?

*Main> let f x = a x >>= b >>= c >> return x 
*Main> f 1 
Just 1 
*Main> f 100 
Nothing 
*Main> 

Dann, wenn das Ergebnis Nichts ist, können wir auf die gewünschte Endzustand mit fromMaybe (oder nur maybe und id, die gleiche Sache) erhalten:

*Main> let g x = maybe x id (f x) 
*Main> g 100 
100 
+1

Dies unterscheidet sich vom OP-Code. Der OP-Code, wenn 'a x' 'Nothing' zurückgibt, führt" x "zu" b ". Monadische Verkettung macht das nicht. – chi

2

Nun können Sie eine a -> a von einem erstellen a -> Maybe a:

repair :: (a -> Maybe a) -> a -> a 
repair f x = fromMaybe x (f x) 

Danach können Sie kombinieren nur (.) und repair:

andThen :: (a -> Maybe a) -> (a -> Maybe a) -> a -> a 
andThen f g = repair g . repair f 

Aber es gibt keine Bibliotheksfunktion für das, da es keine allgemeine Möglichkeit, einen Wert aus einem Monad zu bekommen.

Verwandte Themen