Почему unsafePartial не работает с простым функтором в PureScript? - PullRequest
0 голосов
/ 05 октября 2019

Если я не допустил простой ошибки, следующие фрагменты кода должны быть функционально идентичными:

-- 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, как я думал, хотя это кажется довольно простым.

1 Ответ

1 голос
/ 05 октября 2019

Это происходит потому, что вывод типа не очень хорошо работает с ограничениями. Он не всегда знает, нужно ли перемещать ограничения наверх или оставлять их на месте. В общем, это неразрешимая проблема, компилятор просто старается изо всех сил.

Попробуйте это в 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

Посмотрите, что случилось? Композиция функции "распределила" ограничение Partial по частям своего аргумента, поскольку неясно, применяется ли ограничение в fromJust ко всему типу или индивидуально к a. На самом деле это может быть ошибкой компилятора, но мне трудно сказать прямо сейчас.

Так что, если вы попытаетесь применить эту композицию функций через <$> к getConnection, компилятор ожидает, что getConnection будет иметьэтот странный тип с двойной вложенностью, которого нет.

Интересно, что вы можете использовать unsafePartial, чтобы удалить ограничение Partial из всей функции fromJust, а не просто возвращаемое значение:

> :t unsafePartial fromJust
forall t4. Maybe t4 -> t4    

Это означает, что вы можете сделать что-то вроде этого:

pg :: forall a. PG a -> Route a
pg sql = connect $ bind (unsafePartial fromJust <$> getConnection) (runPG sql)
...