2015-05-13 14 views
5

Moje gut mówi mi, że nic w pobliżu makr lub gimnastyki typu złożonego nie może rozwiązać tego pytania w ogólnym przypadku. Czy Shapeless lub Scalaz mogą mi w tym pomóc? Oto konkretny instancji problemu z n = 2, ale rozwiązanie szukam byłoby trzymać dla wszystkich rozsądnych wartości N:N-Tuple opcji opcji N-Tuple

foo((Some(1), Some("bar"))) == Some((1, "bar")) 
foo((None, Some("bar"))) == None 
foo((Some(1), None)) == None 

Ponownie, to nie jest duplikatem this question, jak ja szukanie ogólnego rozwiązania dla N-krotek. Znajdujące się tam odpowiedzi są wyspecjalizowane w 2-krotkach.

Czy utknąłem przy pisaniu makra, czy też Shapeless/Scalaz może zaoszczędzić dzień?

Odpowiedz

5

shapeless-contrib czyni to całkiem proste:

import shapeless._, ops.hlist.Tupler, contrib.scalaz._, scalaz._, Scalaz._ 

def foo[T, L <: HList, O <: HList](t: T)(implicit 
    gen: Generic.Aux[T, L], 
    seq: Sequencer.Aux[L, Option[O]], 
    tup: Tupler[O] 
): Option[tup.Out] = seq(gen.to(t)).map(tup(_)) 

Wymaga to elementy w argumencie być statycznie wpisane jako Option:

scala> foo((some(1), some("bar"))) 
res0: Option[(Int, String)] = Some((1,bar)) 

scala> foo((none[Int], some("bar"))) 
res1: Option[(Int, String)] = None 

scala> foo((some(1), none[String])) 
res2: Option[(Int, String)] = None 

Jak Alexandre Archambault wspomniano na Gitter, jest to również możliwe, aby napisać a (a raczej 10), w której bierzesz krotkę z elementami statycznie wpisanymi jako Some lub None i uzyskaj wynik statycznie wpisany jako Some lub None. Może to mieć zastosowanie w niektórych sytuacjach, ale ogólnie rzecz biorąc, jeśli masz coś statycznie wpisanego jako Some[A], powinieneś po prostu go reprezentować jako A i domyślam się, że prawdopodobnie chcesz wersję mniejszego poziomu.

pamiętać, że bezkształtne-contrib za Sequencer działa na każdej aplikacyjnej funktora, nie tylko Option, co oznacza, że ​​można dość łatwo przerobić moje foo wziąć typ parametru F[_]: Applicative i zwracają F[T]. Możesz również rzucić własną, mniej ogólną wersję, która działała tylko pod numerem Option, a implementacja prawdopodobnie byłaby trochę prostsza niż wersja bezkształtna-contrib.