How to define function signatures partially in Haskell?

后端 未结 6 1205
刺人心
刺人心 2021-02-03 17:54

Starting point:

fn :: [a] -> Int
fn = (2 *) . length

Let\'s say we only want to constrain the return value, then we could write:

6条回答
  •  遇见更好的自我
    2021-02-03 18:15

    If the type of your fn can be automatically inferred without a signature, and you merely wish the compiler to check whether the inferred type is of the right form, you might use something along the following.

    The idea is to write something such as

    fnSig :: exists _1 _2. forall a. _1 a -> _2
    fnSig = fn
    

    except that Haskell does not allow the existential types above. However, existential types can be emulated using higher-rank types as follows:

    {-# LANGUAGE RankNTypes #-}
    fnSig :: (forall _1 _2.
                (forall a. _1 a -> _2)   -- your actual type, _'s are the unknowns
              ->r)->r
    fnSig = \k->k fn                     -- the compiler infers _1=[] , _2=Int
    
    -- fn :: [] a -> Int
    fn = (2 *) . length
    

    The above "trick" is essentially the same as the one used in e.g. runST.

    Alternatively, one could declare an ad-hoc existential data type.

    {-# LANGUAGE GADTs #-}
    data Ex where Ex :: (forall a. _1 a -> _2) -> Ex
    fnSig = Ex fn
    

    which should force the compiler to perform the same type checking.

提交回复
热议问题