Estoy tratando de hacer coincidir el patrón en Data.Typeable.TypeRep en el siguiente código:

import Data.Typeable (TypeRep, typeOf)

tyI = typeOf (1    :: Int)
tyD = typeOf (3.14 :: Double)
tyB = typeOf (True :: Bool)

func1 :: TypeRep -> Bool
func1 tyI = False
func1 tyD = False
func1 _ = True

func2 :: TypeRep -> Bool
func2 tr = case tr of
    tyI -> False
    tyD -> False
    _   -> True

func3 :: TypeRep -> Bool
func3 tr = if tr == tyI then False else
           if tr == tyD then False else
           True

... y recibo estas advertencias sobre la compilación:

[1 of 1] Compiling Main             ( /home/[..]/test.hs, interpreted )

/home/[..]/test.hs:8:1: Warning:
    Pattern match(es) are overlapped
    In an equation for ‘func1’:
        func1 tyD = ...
        func1 _ = ...

/home/[..]/test.hs:23:12: Warning:
    Pattern match(es) are overlapped
    In a case alternative:
        tyD -> ...
        _ -> ...
Ok, modules loaded: Main.

Además, obtengo resultados sorprendentes:

*Main> func1 tyI
False
*Main> func1 tyD
False
*Main> func1 tyB
False -- !!!

*Main> func2 tyI
False
*Main> func2 tyD
False
*Main> func2 tyB
False -- !!!

*Main> func3 tyI
False
*Main> func3 tyD
False
*Main> func3 tyB
True -- Ok!

Entonces, solo la última función func3 parece producir los resultados esperados. ¿Qué debo hacer para usar las funciones de coincidencia de patrones (func1) y caso (func2) para que funcionen correctamente en TypeReps?

0
Janthelme 22 ago. 2016 a las 17:24

2 respuestas

La mejor respuesta

El problema es que tyI y tyD se consideran variables ordinarias (en lugar de compararlas con las constantes globales del mismo nombre) en la coincidencia de patrones. El siguiente código es completamente equivalente al suyo.

func1 :: TypeRep -> Bool
func1 x = False
func1 y = False
func1 _ = True

func2 :: TypeRep -> Bool
func2 tr = case tr of
    x -> False
    y -> False
    _ -> True

Como ha observado en func3, la forma de resolver esto es hacer explícita la comparación. También puedes hacerlo con guardias:

func4 :: TypeRep -> Bool
func4 tr | tr == tyI = False
         | tr == tyD = False
         | otherwise = True

En general, las únicas cosas permitidas en el lado izquierdo de los iguales contra los que puede hacer coincidir patrones son los constructores. La única excepción son los literales numéricos, y notará que usarlos en patrones incurre en una restricción Eq en la función como un todo

even :: (Num a, Eq a) => a -> Bool
even 0 = True
even 1 = False
even n = even (n-2)

Se agregan excepciones similares a esta regla si agrega OverloadedLists y OverloadedStrings. La regla sigue siendo válida para casi todos los casos.

3
dfeuer 22 ago. 2016 a las 18:21

El tyI aquí:

func1 :: TypeRep -> Bool
func1 tyI = False

No tiene nada que ver con el tyI definido aquí:

tyI = typeOf (1    :: Int)

De hecho, su definición de func1 podría haberse escrito:

func1 :: TypeRep -> Bool
func1 x = False

Y lo mismo vale para func2 - las variables tyI, tyB y tyD son solo nombres de variables de patrón y no se refieren a sus enlaces globales.

Sin embargo, su uso de tyI y tyD en func3 se refiere a las definiciones globales, por eso func3 tyB devuelve True.

3
ErikR 22 ago. 2016 a las 14:41