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
没有我想象的那么有用。