我会忽略HoleyMonoid库。
我们需要自然数:
data Nat = Z | S Nat
他们提升到型A级单:与
data Listy (b :: a -> *) :: [a] -> * where
Nilly :: Listy b '[]
Consy :: b x -> Listy b xs -> Listy b (x ': xs)
然后:
data Natty :: Nat -> * where
Zy :: Natty Z
Sy :: Natty n -> Natty (S n)
类型existentials的名单
type Natties = Listy Natty
我们可以定义
adder :: Natties ns -> Adder ns
其中ns :: [Nat]
。 Adder
类型系列定义如下:
type family Adder (ns :: [Nat]) :: * where
Adder '[] = Int
Adder (n ': ns) = If (NatEq n (S (S (S (S (S Z)))))) Int (Int -> Adder ns)
即,折叠列表Nat
s,对列表中的每个数字加上(Int ->)
,直到遇到5
(在Nat
表单中)。它实际上应该是这样的
if_then_else_ b x y = if b then x else y
type family Adder (ns :: [Nat]) :: * where
Adder '[] = Int
Adder (n ': ns) = 'if_then_else_ (n '== 'fromInt 5) Int (Int -> Adder ns)
但GHC引发一些令人毛骨悚然的错误,我不想了解。
的NatEq
型系列是明显的方式来定义:
type family NatEq n m :: Bool where
NatEq Z Z = True
NatEq Z (S m) = False
NatEq (S n) Z = False
NatEq (S n) (S m) = NatEq n m
我们需要在价值层面来比较Natty
秒。两个Natty
s为相等,当且仅当它们由相同数量的索引(这就是为什么Natty
是一个单):
nattyEq :: Natty n -> Natty m -> Booly (NatEq n m)
nattyEq Zy Zy = Truly
nattyEq Zy (Sy m) = Falsy
nattyEq (Sy n) Zy = Falsy
nattyEq (Sy n) (Sy m) = nattyEq n m
哪里Booly
是另一个单:
data Booly :: Bool -> * where
Truly :: Booly True
Falsy :: Booly False
最后,adder
定义:
adder = go 0 where
go :: Int -> Natties ns -> Adder ns
go i Nilly = 0
go i (Consy n ns) = case nattyEq n (Sy (Sy (Sy (Sy (Sy Zy))))) of
Truly -> i + 100
Falsy -> \a -> go (i + a) ns
iee求和所有参数,直到遇到5
(以Natty
的形式),并添加100
。如果列表中没有5
,则返回0
。
测试:
list = Consy Zy $ Consy (Sy Zy) $ Consy (Sy (Sy (Sy (Sy (Sy Zy))))) $ Consy Zy $ Nilly
main = do
print $ adder (Consy Zy $ Consy (Sy Zy) $ Nilly) 3 9 -- 0
print $ adder list 6 8 -- 114
print $ adder (Consy (Sy (Sy Zy)) list) 1 2 3 -- 106
的code。
那么,“加法器”应该是什么类型?显然你想要的类型取决于列表的长度。这将是[依赖类型](https://en.wikipedia.org/wiki/Dependent_type)。 Haskell不是([相当](http://stackoverflow.com/questions/12961651/why-not-be-dependently-typed/13241158#13241158))依赖类型的语言,所以这是不可能的。有什么可行的是根据你给出的参数来决定类型,并在运行时崩溃,当这与列表不符时......但这不完全是Haskell惯用的。 – leftaroundabout
不适用于定期列表。使用GADT-y列表,您可能会获得类似的例如如http://stackoverflow.com/a/25422805/3234959 – chi
@leftaroundabout它可能不是惯用的,但这基本上是'Text.Printf'的作用。除了运行时检查,这个方法还有一个问题,就是它不能处理像'show'这样的多态函数。 –