Compact vs full/verbose 逆 combinator/operator 在 Curry 中的定义
Compact vs full/verbose definition of the inverse combinator/operator in Curry
基于 Haskell 的 KiCS2 implementation of Curry by Wolfgang Jeltsch, A Taste of Curry 的相当有趣的 2013 介绍 post,为 inverse
组合子提供了以下定义:
inverse :: (a -> b) -> (b -> a)
inverse f y | f x =:= y = x where x free
(注意: 这会做类似 inverse (+1) 3 == 2
和 inverse (*3) 12 == 4
和 inverse htmlHodeToStr == parseHtmlNode
的事情,以及其他的无限难以置信的好东西,对于不熟悉库里的路人)
此外,它还提供了(非确定性)split :: [a] -> ([a], [a])
函数的 2 个替代但等效的定义:
split :: [a] -> ([a],[a])
split list | front ++ rear =:= list = (front,rear)
和
split' :: [a] -> ([a],[a])
split' (xs ++ ys) = (xs,ys)
以及其他一些颇具启发性的定义,但超出了本 post.
的范围
然而,我的想法使我尝试本着 split
和 split'
的精神对 inverse
进行另一种紧凑的定义:
inverse' :: (a -> b) -> (b -> a)
inverse' f (f x) = x
另一方面,这会导致以下错误:
Undefined data constructor `f'
我的问题:为什么 Curry 将可能的函数模式 (f x)
中的 f
解释为数据构造函数,而 ++
在(也是功能性的)模式中 (xs ++ ys)
作为函数名称?
换句话说,split' (xs ++ ys) = (xs,ys)
中的xs
和ys
似乎正好类似于x
在 inverse' f (f x) = x
.
或者如果与 split'
的类比不是很明显,请考虑 prefix (xs ++ _) = xs
或 orig (1 + x) = x
等,它们都可以编译并且 运行 就好了。
P.S。与原来的 post 相比,为了让这个问题更容易理解,我稍微调整了名称和类型签名。
简单来说,f x
等函数式模式的语法要求函数f
是在inverse'
范围内可访问的已定义函数,这就是为什么[=19] =] 有效,而 f x
无效。
这是受功能模式实施的推动。它们被转换为对原始运算符 =:<=
的调用,执行一种 "lazy" 统一(惰性,因为它可能将自由变量绑定到表达式而不是值),其中出现在模式中的变量被引入为新鲜的逻辑变量。因此,函数
f (id x) = x
转换为
f y | id x =:<= y = x where x free
如果函数模式中的函数现在是一个变量,那么就必须猜测任意函数,这在 Curry 中是不支持的。
您现在可能会遇到 f
并不是真正的自由变量,因为它是由 inverse'
的第一个参数决定的,这确实是事实。 inverse'
的定义也使用了非线性模式的语法(因为 f
出现了两次),它的翻译用新的变量替换了重复出现的变量,然后通过严格统一统一了以前重复出现的变量。例如,
pair (x, x) = success
相当于定义
pair' (x, y) | x =:= y = success
这样您的示例就会转换为
inverse' f y | f =:= g & g x =:<= y = x where g, x free
注意,这需要函数的严格统一,目前KiCS2不支持。但是,此定义适用于 PAKCS。
然而,如果我们进一步简化这个定义,我们得到
inverse' f y | f x =:<= y = x where x free
并且此定义最终在 PAKCS 和 KiCS2 中都按预期工作。
请注意,一般不建议显式使用原始运算符 =:<=
,因为它可能会将逻辑变量绑定到表达式而不是值,从而违反逻辑变量的语义(包含所有 values 某种类型,但不是表达式)。功能模式的转换确保无法观察到这种违规行为,但如果直接使用 =:<=
可能会被观察到。
最后,还有一个用于 PAKCS 和 KiCS2 的库 FunctionInversion
,它提供了 invf1
到 invf5
的函数,用于反演具有不同参数的函数。
此限制有语义上的原因(因此自动脱糖是不合理的)。从概念上讲,功能模式的语义是通过评估(通过缩小)数据术语的功能模式并用这些数据术语替换功能模式来定义的,以便它们充当标准模式。为了将这个想法用作构造性定义,需要在函数模式中使用的函数定义在 "lower level" 上,而不是包含函数模式的函数。因此,必须存在所有功能的级别映射。这在 paper on functional patterns 中有详细描述(但当前编译器未检查)。因此,函数模式中的函数变量是不允许的。
有人可能会考虑扩展它,但这超出了当前功能模式的基础。
基于 Haskell 的 KiCS2 implementation of Curry by Wolfgang Jeltsch, A Taste of Curry 的相当有趣的 2013 介绍 post,为 inverse
组合子提供了以下定义:
inverse :: (a -> b) -> (b -> a)
inverse f y | f x =:= y = x where x free
(注意: 这会做类似 inverse (+1) 3 == 2
和 inverse (*3) 12 == 4
和 inverse htmlHodeToStr == parseHtmlNode
的事情,以及其他的无限难以置信的好东西,对于不熟悉库里的路人)
此外,它还提供了(非确定性)split :: [a] -> ([a], [a])
函数的 2 个替代但等效的定义:
split :: [a] -> ([a],[a])
split list | front ++ rear =:= list = (front,rear)
和
split' :: [a] -> ([a],[a])
split' (xs ++ ys) = (xs,ys)
以及其他一些颇具启发性的定义,但超出了本 post.
的范围然而,我的想法使我尝试本着 split
和 split'
的精神对 inverse
进行另一种紧凑的定义:
inverse' :: (a -> b) -> (b -> a)
inverse' f (f x) = x
另一方面,这会导致以下错误:
Undefined data constructor `f'
我的问题:为什么 Curry 将可能的函数模式 (f x)
中的 f
解释为数据构造函数,而 ++
在(也是功能性的)模式中 (xs ++ ys)
作为函数名称?
换句话说,split' (xs ++ ys) = (xs,ys)
中的xs
和ys
似乎正好类似于x
在 inverse' f (f x) = x
.
或者如果与 split'
的类比不是很明显,请考虑 prefix (xs ++ _) = xs
或 orig (1 + x) = x
等,它们都可以编译并且 运行 就好了。
P.S。与原来的 post 相比,为了让这个问题更容易理解,我稍微调整了名称和类型签名。
简单来说,f x
等函数式模式的语法要求函数f
是在inverse'
范围内可访问的已定义函数,这就是为什么[=19] =] 有效,而 f x
无效。
这是受功能模式实施的推动。它们被转换为对原始运算符 =:<=
的调用,执行一种 "lazy" 统一(惰性,因为它可能将自由变量绑定到表达式而不是值),其中出现在模式中的变量被引入为新鲜的逻辑变量。因此,函数
f (id x) = x
转换为
f y | id x =:<= y = x where x free
如果函数模式中的函数现在是一个变量,那么就必须猜测任意函数,这在 Curry 中是不支持的。
您现在可能会遇到 f
并不是真正的自由变量,因为它是由 inverse'
的第一个参数决定的,这确实是事实。 inverse'
的定义也使用了非线性模式的语法(因为 f
出现了两次),它的翻译用新的变量替换了重复出现的变量,然后通过严格统一统一了以前重复出现的变量。例如,
pair (x, x) = success
相当于定义
pair' (x, y) | x =:= y = success
这样您的示例就会转换为
inverse' f y | f =:= g & g x =:<= y = x where g, x free
注意,这需要函数的严格统一,目前KiCS2不支持。但是,此定义适用于 PAKCS。
然而,如果我们进一步简化这个定义,我们得到
inverse' f y | f x =:<= y = x where x free
并且此定义最终在 PAKCS 和 KiCS2 中都按预期工作。
请注意,一般不建议显式使用原始运算符 =:<=
,因为它可能会将逻辑变量绑定到表达式而不是值,从而违反逻辑变量的语义(包含所有 values 某种类型,但不是表达式)。功能模式的转换确保无法观察到这种违规行为,但如果直接使用 =:<=
可能会被观察到。
最后,还有一个用于 PAKCS 和 KiCS2 的库 FunctionInversion
,它提供了 invf1
到 invf5
的函数,用于反演具有不同参数的函数。
此限制有语义上的原因(因此自动脱糖是不合理的)。从概念上讲,功能模式的语义是通过评估(通过缩小)数据术语的功能模式并用这些数据术语替换功能模式来定义的,以便它们充当标准模式。为了将这个想法用作构造性定义,需要在函数模式中使用的函数定义在 "lower level" 上,而不是包含函数模式的函数。因此,必须存在所有功能的级别映射。这在 paper on functional patterns 中有详细描述(但当前编译器未检查)。因此,函数模式中的函数变量是不允许的。
有人可能会考虑扩展它,但这超出了当前功能模式的基础。