OK.Да.Определенно, добавляя числовой тип вокруг рекурсивных экземпляров.
Во-первых, несколько шаблонов:
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
Ваш nat:
data Zero
data Succ n
Рекурсивный компоновщик для variadicфункции, теперь с аргументом n :
class BuildList n a r | r -> a where
build' :: n -> [a] -> a -> r
Базовый случай: остановка при достижении Zero
:
instance BuildList Zero a [a] where
build' _ l x = reverse $ x:l
В противном случае, уменьшение на единицуи повторить:
instance BuildList n a r => BuildList (Succ n) a (a->r) where
build' (_ :: Succ n) l x y = build' (undefined :: n) (x:l) y
Теперь мы хотим выполнить цикл только 3 раза, поэтому запишите это:
build :: BuildList (Succ (Succ Zero)) a r => a -> r
build x = build' (undefined :: Succ (Succ Zero)) [] x
Готово.
Тестирование:
> build "one" "two" "three" :: [[Char]]
["one","two","three"]
Ошибки меньше или больше:
*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]])