Haskell Data.Function';s`on`函数可以推广到n元函数吗?
在基本包中,包含一个函数Haskell Data.Function';s`on`函数可以推广到n元函数吗?,haskell,Haskell,在基本包中,包含一个函数on:(b->b->c)->(a->b)->a->a->c,它类似于一元函数的(::(b->c)->(a->b)->a->c,因此我尝试编写一个函数on'::Int->…,作为一个泛化,这样我就可以在'1长度求反上编写,“2长度比较”上的,等等,但是这样的函数不会进行类型检查,因为“的第三个参数上的函数结果的类型取决于第一个参数 我怎样才能开始编写这样一个函数呢?也许我必须用自定义数据类型包装函数,这样组合函数的类型只取决于第一个参数的类型和最终结果的类型?这里有一种可能
on:(b->b->c)->(a->b)->a->a->c
,它类似于一元函数的(::(b->c)->(a->b)->a->c
,因此我尝试编写一个函数on'::Int->…
,作为一个泛化,这样我就可以在'1长度求反上编写,“2长度比较”上的,等等,但是这样的函数不会进行类型检查,因为“
的第三个参数上的函数结果的类型取决于第一个参数
我怎样才能开始编写这样一个函数呢?也许我必须用自定义数据类型包装函数,这样组合函数的类型只取决于第一个参数的类型和最终结果的类型?这里有一种可能的方法。我们从定义类型级自然开始
{-# 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
然后,我们为
上的
在这些自然语言上引入一个自定义类,并以归纳的方式为每个国家语言实现它
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
不是由类型决定的,它是不明确的,因此我必须显式地传递它(通过类型应用程序——如上所述——或代理)。然而,要通过它,我需要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仍然使用新的Skolem类型常量c0
,这使得它失败
我还尝试让这个家族内射,但失败了。Cf Haskell支持的“依赖类型”虽然有点小,但很麻烦。我想你可以用一个类型族在一个类型级别上建立索引。有关更多信息,请参阅Agda,它有一个足够表达的类型系统,可以以“明显”的方式完成这项工作。该系列不是内射的:f0a(a->a)
和f1a
具有相同的图像。@gallais确实!正因为如此,类型是不明确的,似乎没有办法将正确的c
引入范围。这使得AllowAmbiguousTypes
没有我想象的那么有用。