为什么 unsafePartial 不能与 PureScript 中的简单仿函数一起使用?
Why does unsafePartial not work with a simple functor in PureScript?
除非我犯了一些简单的错误,否则以下代码片段在功能上应该是相同的:
-- This code does not compile
pg :: forall a. PG a -> Route a
pg sql = connect $ apply (runPG sql) (unsafePartial <<< fromJust <$> getConnection)
-- This code does not compile
pg sql = connect $ do
connection <- unsafePartial <<< fromJust <$> getConnection
runPG sql connection
-- This code does work
pg sql = connect $ do
connection <- getConnection
runPG sql $ unsafePartial $ fromJust connection
为了帮助理解这一点,以下是相关类型:
-- Route has a MonadAff instance and all the usual stuff
newtype Route a = Route (ReaderT RouteState Aff a)
-- `connect` makes a connection to Postgres and injects it into the environment.
connect :: forall a. Route a -> Route a
getConnection :: Route (Maybe Connection)
-- PG has a MonadAff instance and all the usual stuff
newtype PG a = PG (ReaderT Connection Aff a)
runPG :: forall m a. MonadAff m => PG a -> Connection -> m a
这是错误:
Error found:
in module AWS.Lambda.Router
at src/AWS/Lambda/Router.purs:176:70 - 176:83 (line 176, column 70 - line 176, column 83)
Could not match constrained type
Partial => t1
with type
{ client :: Client
, pool :: Pool
}
while trying to match type { client :: Client
, pool :: Pool
}
with type Partial => t1
while checking that expression getConnection
has type t0 (Maybe (Partial => t1))
in value declaration pg
where t0 is an unknown type
t1 is an unknown type
See https://github.com/purescript/documentation/blob/master/errors/ConstrainedTypeUnified.md for more information,
or to contribute content related to this error.
spago: Failed to build.
我认为这里发生了两件事之一。要么我犯了一些愚蠢的语法错误,要么我没有像我想的那样理解 Partial
,尽管它看起来很简单。
发生这种情况是因为类型推断不能很好地处理约束。它并不总是知道是否需要将约束移动到顶部或将它们留在原地。一般来说,这是一个无法确定的问题,编译器只是尽力而为。
在 REPL 中试试这个:
> :t fromJust
forall a. Partial => Maybe a -> a
> :t unsafePartial
forall a. (Partial => a) -> a
> :t unsafePartial <<< fromJust
forall t2. Partial => Maybe (Partial => t2) -> t2
看看发生了什么?函数组合对其参数的各个部分具有 "distributed" Partial
约束,因为不清楚 fromJust
中的约束是适用于整个类型还是单独适用于 a
。这实际上可能是一个编译器错误,但现在对我来说很难说。
因此,如果您尝试通过 <$>
将此函数组合应用到 getConnection
,编译器期望 getConnection
具有这种奇怪的双重嵌套类型,而事实并非如此。
有趣的是,您可以使用 unsafePartial
从整个函数 fromJust
中删除 Partial
约束,而不仅仅是它的 return 值:
> :t unsafePartial fromJust
forall t4. Maybe t4 -> t4
这意味着您可以这样做:
pg :: forall a. PG a -> Route a
pg sql = connect $ bind (unsafePartial fromJust <$> getConnection) (runPG sql)
除非我犯了一些简单的错误,否则以下代码片段在功能上应该是相同的:
-- This code does not compile
pg :: forall a. PG a -> Route a
pg sql = connect $ apply (runPG sql) (unsafePartial <<< fromJust <$> getConnection)
-- This code does not compile
pg sql = connect $ do
connection <- unsafePartial <<< fromJust <$> getConnection
runPG sql connection
-- This code does work
pg sql = connect $ do
connection <- getConnection
runPG sql $ unsafePartial $ fromJust connection
为了帮助理解这一点,以下是相关类型:
-- Route has a MonadAff instance and all the usual stuff
newtype Route a = Route (ReaderT RouteState Aff a)
-- `connect` makes a connection to Postgres and injects it into the environment.
connect :: forall a. Route a -> Route a
getConnection :: Route (Maybe Connection)
-- PG has a MonadAff instance and all the usual stuff
newtype PG a = PG (ReaderT Connection Aff a)
runPG :: forall m a. MonadAff m => PG a -> Connection -> m a
这是错误:
Error found:
in module AWS.Lambda.Router
at src/AWS/Lambda/Router.purs:176:70 - 176:83 (line 176, column 70 - line 176, column 83)
Could not match constrained type
Partial => t1
with type
{ client :: Client
, pool :: Pool
}
while trying to match type { client :: Client
, pool :: Pool
}
with type Partial => t1
while checking that expression getConnection
has type t0 (Maybe (Partial => t1))
in value declaration pg
where t0 is an unknown type
t1 is an unknown type
See https://github.com/purescript/documentation/blob/master/errors/ConstrainedTypeUnified.md for more information,
or to contribute content related to this error.
spago: Failed to build.
我认为这里发生了两件事之一。要么我犯了一些愚蠢的语法错误,要么我没有像我想的那样理解 Partial
,尽管它看起来很简单。
发生这种情况是因为类型推断不能很好地处理约束。它并不总是知道是否需要将约束移动到顶部或将它们留在原地。一般来说,这是一个无法确定的问题,编译器只是尽力而为。
在 REPL 中试试这个:
> :t fromJust
forall a. Partial => Maybe a -> a
> :t unsafePartial
forall a. (Partial => a) -> a
> :t unsafePartial <<< fromJust
forall t2. Partial => Maybe (Partial => t2) -> t2
看看发生了什么?函数组合对其参数的各个部分具有 "distributed" Partial
约束,因为不清楚 fromJust
中的约束是适用于整个类型还是单独适用于 a
。这实际上可能是一个编译器错误,但现在对我来说很难说。
因此,如果您尝试通过 <$>
将此函数组合应用到 getConnection
,编译器期望 getConnection
具有这种奇怪的双重嵌套类型,而事实并非如此。
有趣的是,您可以使用 unsafePartial
从整个函数 fromJust
中删除 Partial
约束,而不仅仅是它的 return 值:
> :t unsafePartial fromJust
forall t4. Maybe t4 -> t4
这意味着您可以这样做:
pg :: forall a. PG a -> Route a
pg sql = connect $ bind (unsafePartial fromJust <$> getConnection) (runPG sql)