2010-10-22 38 views
8

Właśnie napisałem tę funkcję, która po prostu bierze parę, której druga wartość jest w jakiejś monadzie, i "wyciąga monadę", aby pokryć całą parę.Czy ta prosta funkcja Haskella ma już znaną nazwę?

unSndM :: Monad m => (a, m c) -> m (a, c) 
unSndM (x, y) = do y' <- y 
        return (x, y') 

Czy jest lepszy i/lub krótszy, czy wolny od punktu, a nawet standardowy sposób wyrażenia tego?

mam tak daleko, jak poniżej, z -XTupleSections włączone ...

unSndM' :: Monad m => (a, m c) -> m (a, c) 
unSndM' (x, y) = y >>= return . (x,) 

Dzięki!

+0

Zasady tagu 'code-golf': http://stackoverflow.com/tags/code-golf/info – Nakilon

+0

Wystarczająco fair. Witryna pozwoliła mi dodać tag, nie informując mnie, że są z nim powiązane reguły. * wzruszenie ramion * – gimboland

Odpowiedz

12

Jedna drobna uwaga: jest to możliwe, aby napisać to za pomocą tylko fmap (bez >>=), więc naprawdę trzeba tylko Functor instancję:

unSndM :: (Functor f) => (a, f c) -> f (a, c) 
unSndM (x, y) = fmap ((,) x) y 

ta wersja jest nieco bardziej ogólne. Aby odpowiedzieć na pytanie dotyczące wersji pointfree, możemy tylko prosić pointfree:

[email protected]% pointfree "unSndM (x, y) = fmap ((,) x) y" 
unSndM = uncurry (fmap . (,)) 

Tak, tak, jeszcze krótsza wersja jest możliwe, ale ja osobiście uważam uncurry trochę trudne do odczytania i uniknąć w większości przypadków.

Gdybym pisząc tę ​​funkcję w mój własny kod, prawdopodobnie używać <$> z Control.Applicative, który nie ogolił jeden znak:

unSndM :: (Functor f) => (a, f c) -> f (a, c) 
unSndM (x, y) = ((,) x) <$> y 

<$> jest po prostu synonimem fmap, i to mi się podoba sprawia, że ​​jest to trochę bardziej przejrzyste.

+1

Tupling również jest wygodnie zamawiany, umożliwiając definicję typu 'unSmdM = uncurry $ fmap. (,) '. Interesująco, typ tej funkcji jest dużo bardziej czytelny/opisowy niż każda z implementacji :) – Anthony

+1

Zgadzam się, ale' unSndM (x, y) = (x,) <$> y' jest całkiem blisko. –

+0

Ooh, nie wiedziałem o pointfree - miłym, dzięki! (Oczywiście wypróbowałem hoogle). Kilka ładnych wersji tutaj, bez dodatkowego importu lub modyfikacji bibliotek ;-) - dziękuję. :-) – gimboland

3

Hoogle jest twoim przyjacielem. Jeśli jedna ze standardowych bibliotek miałaby to hoogle dla "Monad m => (a, m b) -> m (a,b)" by to znalazło. Zauważ, że funkcja nadal może być w pakiecie hackage, ale często nie jest warta dodatkowej instalacji dep tylko dla małych funkcji, takich jak ta.

+0

"często nie jest warta dodatkowej depozytu na budowę tylko dla małych funkcji takich jak ta" - to taka smutna rzecz :( – Fresheyeball

13

Jeśli Traversable i Foldable instancje dla (,) x) były w bibliotece (i przypuszczam, że muszę trochę winy za ich braku) ...

instance Traversable ((,) x) where 
    traverse f (x, y) = (,) x <$> f y 

instance Foldable ((,) x) where 
    foldMap = foldMapDefault 

... wtedy ta (czasami określana jako "siła") byłaby specjalizacją Data.Traversable.sequence.

sequence :: (Traversable t, Monad m) => t (m a) -> m (t a) 

tak

sequence :: (Monad m) => ((,) x) (m a) -> m (((,) x) a) 

tj

sequence :: (Monad m) => (x, m a) -> m (x, a) 

W rzeczywistości sekwencja naprawdę nie używać pełnej mocy Monad: Applicative zrobi. Co więcej, w tym przypadku parowanie-z-x jest liniowe, a więc traverse raczej niż inne przypadkowe kombinacje pure i <*> i (jak wskazano gdzie indziej) potrzebujesz tylko m, aby mieć strukturę funkturalną.

+1

Brzmi jak narodziny propozycji bibliotek @ :-) – sclv

+1

Miło, a koszt jest również sekwencją! http://hackage.haskell.org/packages/archive/category-extras/0.53.5/doc/html/src/Control-Functor-Strong.html –

+1

Zadziwiające rzeczy. Wiedziałem, że to wygląda na tyle proste, że teoretyk kategorii musiał już nadać mu nazwę. :-) – gimboland

Powiązane problemy