回答:
まあ、再帰的な解決策は確かに通常の、そして実際にはHaskellの素晴らしいものですが、そのとき要素の数を制限するのは少し難しいです。したがって、問題の簡単な解決策として、最初に、bradmから提供された愚かながらも機能する問題を検討してください。
再帰的ソリューションの秘訣は、「カウンター」変数を再帰に渡し、最大許容数に達したときに、より多くの要素のコンスを無効にすることです。これはGADTでうまく実行できます。
{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeInType, StandaloneDeriving #-}
import Data.Kind
import GHC.TypeLits
infixr 5 :#
data ListMax :: Nat -> Type -> Type where
Nil :: ListMax n a
(:#) :: a -> ListMax n a -> ListMax (n+1) a
deriving instance (Show a) => Show (ListMax n a)
その後
*Main> 0:#1:#2:#Nil :: ListMax 5 Int
0 :# (1 :# (2 :# Nil))
*Main> 0:#1:#2:#3:#4:#5:#6:#Nil :: ListMax 5 Int
<interactive>:13:16: error:
• Couldn't match type ‘1’ with ‘0’
Expected type: ListMax 0 Int
Actual type: ListMax (0 + 1) Int
• In the second argument of ‘(:#)’, namely ‘5 :# 6 :# Nil’
In the second argument of ‘(:#)’, namely ‘4 :# 5 :# 6 :# Nil’
In the second argument of ‘(:#)’, namely ‘3 :# 4 :# 5 :# 6 :# Nil’
完全を期すために、「醜い」代替アプローチを追加しましょう。ただし、これは基本的なものです。
これMaybe a
は、値がの形式Nothing
またはJust x
一部の型であることに注意してくださいx :: a
。
したがって、上記の値を再解釈することによりMaybe a
、リストに0または1つの要素を含めることができる「制限付きリストタイプ」と見なすことができます。
ここで、(a, Maybe a)
要素を1つ追加するだけで、リストは1つ((x1, Nothing)
)または2つ((x1, Just x2)
)の要素を持つことができる「リストタイプ」になります。
したがって、Maybe (a, Maybe a)
は「リストタイプ」であり、リストにはゼロ(Nothing
)、1(Just (x1, Nothing)
)、または2((Just (x1, Just x2)
)の要素を含めることができます。
これで、続行方法を理解できるようになります。これは使用するのに便利な解決策ではありませんが、(IMO)とにかくそれを理解するための素晴らしい練習であることを再度強調しておきます。
Haskellのいくつかの高度な機能を使用して、タイプファミリーを使用して上記を一般化できます。
type family List (n :: Nat) (a :: Type) :: Type where
List 0 a = ()
List n a = Maybe (a, List (n-1) a)
a
のs 。Either () (a, Either () (a, Either () (a, Either () ())))
foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3]