代码之家  ›  专栏  ›  技术社区  ›  Dario

如何使haskell计算正确的多态类型?

  •  7
  • Dario  · 技术社区  · 16 年前

    我刚刚意识到这一点是多么有用 on -函数可以是。

    前任:

    orderByLength = sortBy (compare `on` length) 
    

    但不幸的是,推断的类型可能有点违反直觉。

    根据定义

    f `on` g = \x y -> f (g x) (g y)
    

    例如,可以更换

    (==) `on` length
    

    具有

    \x y -> (length x) == (length y)
    

    但两者都有不同的类型!

    第一个有 [a] -> [a] -> Bool 而第二个具有正确的、更通用的 [a] -> [b] -> Bool .

    这显然不允许使用正确的术语,比如 (on (==) length) [1, 2, 3] ["a", "b", "c"] (应该产生 True 但现在连类型检查都失败了)。

    我知道这个限制是由于 first-rank types 但如何克服这一点呢?有人能制定一个 能够正确处理多态函数(使用通用量化/秩n类型)?

    1 回复  |  直到 16 年前
        1
  •  3
  •   ephemient    16 年前
    {-# LANGUAGE Rank2Types #-}
    on' :: (a -> a -> b) -> (forall d. c d -> a) -> c e -> c f -> b
    on' f g x y = f (g x) (g y)
    

    这导致

    Prelude> :t on' (==)
    on' (==) :: (Eq a) => (forall d. c d -> a) -> c e -> c f -> Bool
    Prelude> :t on' (==) length
    on' (==) length :: [e] -> [f] -> Bool
    

    另一方面,这个签名也使 flip on' id 非法的,这有点不可取。


    {-# LANGUAGE TemplateHaskell #-}
    import Language.Haskell.TH
    onE f g = do
        x <- newName "x"
        y <- newName "y"
        lamE [varP x, varP y] $ f `appE` (g `appE` varE x) `appE` (g `appE` varE y)
    
    Prelude> :set -XTemplateHaskell
    Prelude> $(onE [|(==)|] [|length|]) [1,2,3] ["a","b","c"]
    True
    Prelude> $(onE [|(==)|] [|id|]) 4 5
    False