Generate function of given arity in Haskell using type numbers

前端 未结 4 1376
一向
一向 2021-02-01 23:40

Assume I have encoded the natural numbers in Haskell types, and that I have a way of adding and subtracting from them:

data Zero
data Succ n
-- ...
4条回答
  •  天命终不由人
    2021-02-01 23:53

    OK. Yes. Definitely, by threading a numeric type around the recursive instances.

    First, some boilerplate:

    {-# LANGUAGE FunctionalDependencies #-}
    {-# LANGUAGE MultiParamTypeClasses  #-}
    {-# LANGUAGE EmptyDataDecls         #-}
    {-# LANGUAGE FlexibleInstances      #-}
    {-# LANGUAGE FlexibleContexts       #-}
    {-# LANGUAGE ScopedTypeVariables    #-}
    

    Your nats:

    data Zero
    data Succ n
    

    A recursive builder for the variadic functions, now with an n argument:

    class BuildList n a r | r -> a where
        build' :: n -> [a] -> a -> r
    

    A base case: stop when we get to Zero:

    instance BuildList Zero a [a] where
        build' _ l x = reverse $ x:l
    

    Otherwise, decrement by one and recurse:

    instance BuildList n a r => BuildList (Succ n) a (a->r) where
        build' (_ :: Succ n) l x y = build' (undefined :: n) (x:l) y
    

    Now, we only want to loop 3 times, so write that down:

    build :: BuildList (Succ (Succ Zero)) a r => a -> r
    build x = build' (undefined :: Succ (Succ Zero)) [] x
    

    Done.

    Testing:

    > build "one" "two" "three" :: [[Char]]
    ["one","two","three"]
    

    Any less or more are errors:

    *Main> build "one" "two" "three" "four" :: [[Char]]
    
    :1:1:
        No instance for (BuildList Zero [Char] ([Char] -> [[Char]]))
    
    *Main> build "one" "two" :: [[Char]]
    
    :1:1:
        No instance for (BuildList (Succ Zero) [Char] [[Char]])
    

提交回复
热议问题