Generate function of given arity in Haskell using type numbers

前端 未结 4 1299
一向
一向 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]]
    
    <interactive>:1:1:
        No instance for (BuildList Zero [Char] ([Char] -> [[Char]]))
    
    *Main> build "one" "two" :: [[Char]]
    
    <interactive>:1:1:
        No instance for (BuildList (Succ Zero) [Char] [[Char]])
    
    0 讨论(0)
  • 2021-02-02 00:02

    Inlining Martijn's code gives a very simple solution:

    zero xs = xs
    suc n xs x = n (xs ++ [x])
    buildList n = n []
    
    0 讨论(0)
  • 2021-02-02 00:13

    Oh, my... FlexibleContexts??? NoMonomorphismRestriction??? Come on, guys, isn't it exactly what TypeFamilies are for?

    {-# LANGUAGE TypeFamilies #-}
    data Zero = Zero
    newtype Succ n = Succ n
    zero = Zero
    one = Succ zero
    two = Succ one
    three = Succ two
    class BuildList n where
        type BL n
        buildListPrefix :: n -> ([String] -> [String]) -> BL n
    instance BuildList Zero where
        type BL Zero = [String]
        buildListPrefix Zero h = h []
    instance BuildList n => BuildList (Succ n) where
        type BL (Succ n) = String -> BL n
        buildListPrefix (Succ n) h s = buildListPrefix n (h . (s:))
    buildList:: BuildList n => n -> BL n
    buildList n = buildListPrefix n id
    
    0 讨论(0)
  • 2021-02-02 00:14

    I see your functional-dependency multiparameter empty-datatype flexibly scoped type variables and raise you a Haskell 98 version! It uses HoleyMonoid which is available on hackage:

    {-# LANGUAGE NoMonomorphismRestriction #-}
    
    import Prelude hiding (id, (.))
    import Control.Category
    import Data.HoleyMonoid
    
    suc n = later (:[]) . n
    
    zero  = id
    one   = suc zero
    two   = suc one
    three = suc two
    
    buildList = run
    

    Testing (feel free to omit any type signatures):

    > run three "one" "two" "three"
    ["one","two","three"]
    
    0 讨论(0)
提交回复
热议问题