這是一種可能的方法。我們從定義類型級別自然開始。
{-# LANGUAGE ScopedTypeVariables, TypeFamilies, DataKinds, TypeApplications,
AllowAmbiguousTypes, MultiParamTypeClasses, FlexibleInstances #-}
{-# OPTIONS -Wall #-}
data Nat = O | S Nat
我們定義a -> a -> ... a -> b
與n
參數。
type family F (n :: Nat) a b where
F 'O a b = b
F ('S n) a b = a -> F n a b
然後介紹了這些土黃的自定義類我們on
,並以感性的方式實現它爲每一個natiral。
class On (n :: Nat) c where
on :: forall a b. F n b c -> (a -> b) -> F n a c
instance On 'O c where
on f _g = f
instance On n c => On ('S n) c where
on f g = \aVal -> on @n @c (f (g aVal)) g
最後一些例子。
fun2 :: String -> String -> String
fun2 x y = "(" ++ x ++ ", " ++ y ++ ")"
fun3 :: String -> String -> String -> String
fun3 x y z = "(" ++ x ++ ", " ++ y ++ ", " ++ z ++ ")"
funG :: Int -> String
funG n = replicate n '#'
test2 :: String
test2 = on @('S ('S 'O)) fun2 funG 1 2
test3 :: String
test3 = on @('S ('S ('S 'O))) fun3 funG 1 2 3
相對題外話注:
我無法找到一個方法來刪除從類型類c
說法。由於c
不是根據類型確定的,因此它是不明確的,因此我必須明確地通過它(通過類型應用程序 - 如上所述 - 或Proxy
)。但是,要通過它,我需要c
在範圍內。如果我從班級中刪除c
,它將超出範圍。如果我使用實例簽名,我可以將c
帶回範圍,但由於類型不明確,GHC不會將其識別爲相同的c
。
OnGeneralization2.hs:18:10: error:
• Couldn't match type ‘F n a c0’ with ‘F n a c’
Expected type: F ('S n) b c -> (a -> b) -> F ('S n) a c
Actual type: F ('S n) b c0 -> (a -> b) -> F ('S n) a c0
NB: ‘F’ is a type function, and may not be injective
The type variable ‘c0’ is ambiguous
• When checking that:
forall a b c. F ('S n) b c -> (a -> b) -> F ('S n) a c
is more polymorphic than:
forall a b c. F ('S n) b c -> (a -> b) -> F ('S n) a c
When checking that instance signature for ‘on’
is more general than its signature in the class
Instance sig: forall a b c.
F ('S n) b c -> (a -> b) -> F ('S n) a c
Class sig: forall a b c.
F ('S n) b c -> (a -> b) -> F ('S n) a c
In the instance declaration for ‘On ('S n)’
注意最後一行:他們是完全一樣的類型,但爲了檢查它們的亞型,GHC依然採用新鮮斯科倫類型常量c0
,這使得它失敗。
我也試圖讓家庭內射,但失敗了。
來源
2017-03-25 09:19:24
chi
參考「依賴類型」,Haskell支持一點但很麻煩。我想你可以通過一個類型級別的自然類型索引來實現。欲瞭解更多信息,請參閱Agda,它具有足夠表現力的類型系統以「明顯」的方式執行此操作。 – luqui