Recentemente, estive enfrentando situações em que preciso passar uma função predicada para outra função, e muitas vezes a lógica que estou procurando é essencialmente "esse valor corresponde a esse padrão?"
A correspondência de padrões parece ser preferida em declarações, do
blocos e compreensões de lista, mas há várias funções que usam um predicado a -> Bool
, nas quais seria muito útil passar de alguma forma em um padrão. Por exemplo, takeWhile
, until
, find
, span
, etc.
Até agora eu venho fazendo \a -> case a of MyCons _ -> True; otherwise -> False
ou escrevendo uma função nomeada à la, let myPred (MyCons _) = True; myPred _ = False in
mas ambas parecem terrivelmente feias e não muito idiomáticas. O caminho "óbvio" (e errado) seria algo parecido, \(MyCons _) -> True
mas isso gera um erro por ser parcial, naturalmente, e mesmo assim parece que deve haver um caminho mais limpo.
Existe uma maneira mais sucinta / limpa de fazer esse tipo de coisa? Ou estou fazendo as coisas da maneira errada?
let
cláusula que você não gosta - embora eu prefira awhere
cláusula equivalente para que isso não atrapalhe a definição principal. Obviamente, se você precisar deste utilitário mais de uma vez, você o definiria como uma função de nível superior.let myPred...
estilo é ruim , mas parece muito mais detalhado do que eu esperaria de uma idéia muito simples, o que me leva a pensar se estou latindo na árvore errada.maybe :: b -> (a -> b) -> Maybe a -> b
ebool :: a -> a -> Bool -> a
, em seguida, usá-la com funções de produção booleana como argumento (s). por exemplomyCons z f (MyCons x) = f x ; myCons z f _ = z
, então liguemyCons False (const True) aMyConsValue
. isto é quase o que você escreveu, apenas possui mais um nível de "indireção" / "abstração" por meio de argumentos funcionais, inseridos nele.Respostas:
Você pode usar a extensão de idioma LambdaCase para usar
\case MyCons _ -> True; _ -> False
, embora isso não salve muitos caracteres.Acredito que você possa escrever uma série de funções
constructedWith :: (Generic a) => (b -> a) -> a -> Bool
,constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Bool
mas não sou competente o suficiente com a Generics para implementá-la sem algumas horas testando as coisas. Vou tentar isso e editar minha resposta se eu puder descobrir ou se é um beco sem saída.EDIT: Sim, você pode fazê-lo! Aqui está um link para o meu código, que implementa tudo do zero:
https://repl.it/@lalaithion/ConstructedWith
No entanto, usar algo como http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html para todo o encanamento de código genérico pode ser melhor.
fonte