请注意以下Haskell术语:
callNTimes :: forall a . Int -> (a -> a) -> a -> a
callNTimes n f 0 = x
callNTimes n f x = f (callNTimes (n-1) f x)
firstOf :: ??????
firstOf n = callNTimes n (\ x y -> x)
如果我们忽略类型并手动规范化函数,firstOf
是一个接收N
然后N
参数的函数,丢弃除第一个之外的所有函数并返回它。 firstOf 3 10 20 30
返回3
。是否可以使用新的依赖类型功能在GHC 8.0中键入该功能?
答案 0 :(得分:5)
我终于设法得到了一个正常工作的版本 - 它并不完全符合您的要求,但它展示了我评论的内容,我认为它非常接近
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Variadic where
data Z a = Z
data S t a = S (t a)
class Var n where
type El n :: *
type Res n :: *
firstOf :: n -> El n -> Res n
instance Var (Z a) where
type El (Z a) = a
type Res (Z a) = a
firstOf Z a = a
instance (El (n a) ~ a, Var (n a)) => Var (S n a) where
type El (S n a) = a
type Res (S n a) = a -> Res (n a)
firstOf (S n) a _ = firstOf n a
以下是一些例子:
λ> firstOf Z 5
5
λ> firstOf (S Z) 5 9
5
λ> firstOf (S (S Z)) 5 8 9
5
λ> firstOf (S (S Z)) "Hi" "World" "Uhu"
"Hi"
如果您对我如何到达那里感兴趣,可以查看编辑历史
S
和Z
作为穷人替换*用于类型级文字,您可以使用此firstOf (S (S Z))
正在等待3 - 那是因为我从Z
= 1参数开始firstOf 3 10 20 30 = 3
这不会做(这会给10
) - 这可能是类型级文字和明显的重载答案 1 :(得分:2)
{-# LANGUAGE GADTs, DataKinds, TypeFamilies, TypeOperators #-}
type family Fun as b where
Fun '[] b = b
Fun (a ': as) b = a -> Fun as b
data SL as where
Sn :: SL '[]
Sc :: SL as -> SL (a ': as)
constN :: SL as -> b -> Fun as b
constN Sn y = y
constN (Sc s) y = \_ -> constN s y
-- 1
main = print $ constN (Sc (Sc (Sc Sn))) 1 "a" [3] True
E.g。 Fun [Int, Bool] [Int] = Int -> Bool -> [Int]
。 SL
是一个允许将列表提升到类型级别的单例。 SL as
上的模式匹配显示as
是[]
或a:as
。在第一种情况下,目标的类型Fun [] b
仅为b
。在第二种情况下,目标具有类型a -> Fun as b
,因此是lambda。
只有GADTs
的简单解决方案:
{-# LANGUAGE GADTs #-}
data T z a where
Tz :: T z z
Ts :: T z b -> T z (a -> b)
constN :: T z a -> z -> a
constN Tz y = y
constN (Ts s) y = \x -> constN s y
-- 1
main = print $ constN (Ts (Ts (Ts Tz))) 1 "a" [3] True