将定点运算符翻译成 Haskell 语言
Translating a fixed-point operator to Haskell language
我正在尝试将这个 JS 定点运算符翻译成 Haskell。
JS:
const fix = F => {
const D = X => F(
t => X(X)(t)
)
return D(D)
};
我的尝试是 (Haskell):
fix' f = d d
where
d x = f (\t -> x x t)
但是,我收到以下错误:
Couldn't match expected type ‘(t2 -> t3) -> t4’
with actual type ‘p’
because type variables ‘t2’, ‘t3’, ‘t4’ would escape their scope
These (rigid, skolem) type variables are bound by the inferred type of d :: (t1 -> t2 -> t3) -> t4
有人知道这里发生了什么吗?
在自应用程序d d
中,d
既是一个a -> r
类型的函数,也是a
类型的参数。因此这两种类型必须是相同的,a ~ (a -> r)
.
Haskell 想要预先完全了解它的类型,所以它不断地用一种替代另一种,最终得到无限类型。
Haskell 中不允许无限类型,但允许递归类型。
我们在这里需要做的就是命名该递归类型:
newtype T r = D { app :: T r -> r }
现在 T r
既是函数类型又是它的参数,对于某些结果类型 r
。
这里T
是类型构造函数,D
是它的数据构造函数,D :: (T r -> r) -> T r
.
上面的记录语法定义了一个新的数据类型(虽然这里使用关键字newtype
,而不是data
)并将其单个字段命名为app
。它还将 app
定义为访问函数 app :: T r -> (T r -> r)
。 (它有点像 D
的逆函数,通常人们会看到这样的函数以“un”为前缀命名,例如 app
可以命名为 unD
。但是这里 app
是有道理的,我们稍后会看到。)
对于 T r
、x :: T r
类型的值 x
,这意味着 x
是/匹配/某个值 D g
,其中 (g = app x) :: T r -> r
,即 app
简单地展开数据构造函数 D
以获得基础值(函数)g
:x = D g ; app x = app (D g) = g
。这就是记录语法在 Haskell.
中的工作方式
现在我们可以写了
{- fix' f = d d
where
d x = f (\t -> x x t) -- applying x to x can't be typed!
-}
fix1 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix1 f = d (D d)
where
d x = f (\t -> app x x t) -- `app`ing x to x is well-typed!
fix2 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix2 f = d (D d)
where
d (D y) = f (\t -> y (D y) t)
fix3 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix3 f = f (\t -> d (D d) t)
where
d (D y) = f (\t -> y (D y) t)
fix4 :: (t -> t) -> t
fix4 f = f (d (D d))
where
d (D y) = f (y (D y))
一切正常。最后一个甚至与内置 fix
.
具有相同的类型
但是Haskell不仅有递归类型。它本身也有递归。实体 是 允许在其自己的 定义 .
中引用 自身
因此正如评论所说,我们真的不需要通过自我应用作为参数传递的值来模拟递归。我们可以递归地使用被定义的函数本身:
fix0 :: (t -> t) -> t
fix0 f = f (fix0 f)
或者我们可以使用递归定义的值:
y :: (t -> t) -> t
y f = x where { x = f x }
关于错误,第二类型错误you get,
prog.hs:3:22: error:
• Occurs check: cannot construct the infinite type:
t1 ~ t1 -> t2 -> t3
• In the first argument of ‘x’, namely ‘x’
In the expression: x x t
In the first argument of ‘f’, namely ‘(\ t -> x x t)’
• Relevant bindings include
t :: t2 (bound at prog.hs:3:15)
x :: t1 -> t2 -> t3 (bound at prog.hs:3:7)
d :: (t1 -> t2 -> t3) -> t4 (bound at prog.hs:3:5)
|
3 | d x = f (\t -> x x t)
| ^
似乎比您提供的那个更切题/更有帮助/。
我正在尝试将这个 JS 定点运算符翻译成 Haskell。
JS:
const fix = F => {
const D = X => F(
t => X(X)(t)
)
return D(D)
};
我的尝试是 (Haskell):
fix' f = d d
where
d x = f (\t -> x x t)
但是,我收到以下错误:
Couldn't match expected type ‘(t2 -> t3) -> t4’
with actual type ‘p’
because type variables ‘t2’, ‘t3’, ‘t4’ would escape their scope
These (rigid, skolem) type variables are bound by the inferred type of d :: (t1 -> t2 -> t3) -> t4
有人知道这里发生了什么吗?
在自应用程序d d
中,d
既是一个a -> r
类型的函数,也是a
类型的参数。因此这两种类型必须是相同的,a ~ (a -> r)
.
Haskell 想要预先完全了解它的类型,所以它不断地用一种替代另一种,最终得到无限类型。
Haskell 中不允许无限类型,但允许递归类型。
我们在这里需要做的就是命名该递归类型:
newtype T r = D { app :: T r -> r }
现在 T r
既是函数类型又是它的参数,对于某些结果类型 r
。
这里T
是类型构造函数,D
是它的数据构造函数,D :: (T r -> r) -> T r
.
上面的记录语法定义了一个新的数据类型(虽然这里使用关键字newtype
,而不是data
)并将其单个字段命名为app
。它还将 app
定义为访问函数 app :: T r -> (T r -> r)
。 (它有点像 D
的逆函数,通常人们会看到这样的函数以“un”为前缀命名,例如 app
可以命名为 unD
。但是这里 app
是有道理的,我们稍后会看到。)
对于 T r
、x :: T r
类型的值 x
,这意味着 x
是/匹配/某个值 D g
,其中 (g = app x) :: T r -> r
,即 app
简单地展开数据构造函数 D
以获得基础值(函数)g
:x = D g ; app x = app (D g) = g
。这就是记录语法在 Haskell.
现在我们可以写了
{- fix' f = d d
where
d x = f (\t -> x x t) -- applying x to x can't be typed!
-}
fix1 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix1 f = d (D d)
where
d x = f (\t -> app x x t) -- `app`ing x to x is well-typed!
fix2 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix2 f = d (D d)
where
d (D y) = f (\t -> y (D y) t)
fix3 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix3 f = f (\t -> d (D d) t)
where
d (D y) = f (\t -> y (D y) t)
fix4 :: (t -> t) -> t
fix4 f = f (d (D d))
where
d (D y) = f (y (D y))
一切正常。最后一个甚至与内置 fix
.
但是Haskell不仅有递归类型。它本身也有递归。实体 是 允许在其自己的 定义 .
中引用 自身因此正如评论所说,我们真的不需要通过自我应用作为参数传递的值来模拟递归。我们可以递归地使用被定义的函数本身:
fix0 :: (t -> t) -> t
fix0 f = f (fix0 f)
或者我们可以使用递归定义的值:
y :: (t -> t) -> t
y f = x where { x = f x }
关于错误,第二类型错误you get,
prog.hs:3:22: error:
• Occurs check: cannot construct the infinite type:
t1 ~ t1 -> t2 -> t3
• In the first argument of ‘x’, namely ‘x’
In the expression: x x t
In the first argument of ‘f’, namely ‘(\ t -> x x t)’
• Relevant bindings include
t :: t2 (bound at prog.hs:3:15)
x :: t1 -> t2 -> t3 (bound at prog.hs:3:7)
d :: (t1 -> t2 -> t3) -> t4 (bound at prog.hs:3:5)
|
3 | d x = f (\t -> x x t)
| ^
似乎比您提供的那个更切题/更有帮助/。