Подтвердить что ты не робот

Haskell - Определен ли порядок действия в случае аппликативного?

При выполнении действия IO, определенного someFun <$> (a :: IO ()) <$> (b :: IO ()), выполняется ли выполнение действий a и b? То есть, могу ли я рассчитывать на то, что a выполняется до b?

Для GHC я вижу, что IO реализовано с использованием State, а также см. здесь, что это аппликативный экземпляр, но не может найдите источник фактической декларации экземпляра. Выполнение через государство предполагает, что различные IO-эффекты должны быть последовательными, но не обязательно определяют их порядок.

Игра в GHCi кажется, что Appliative сохраняет порядок эффекта, но является ли это какой-то универсальной гарантией или спецификой GHC? Мне было бы интересно узнать подробности.

import System.Time
import Control.Concurrent
import Data.Traversable
let prec (TOD a b) = b
fmap (map prec) (sequenceA $ replicate 5 (threadDelay 1000 >> getClockTime))

[641934000000,642934000000,643934000000,644934000000,645934000000]

Спасибо!

4b9b3361

Ответ 1

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

Однако из документации для Applicative:

Если f также является Monad, оно должно удовлетворять pure= return и (<*>)= ap (что означает, что pure и <*> удовлетворяют законам аппликативного функтора).

Определение ap таково: от Control.Monad:

ap :: (Monad m) => m (a -> b) -> m a -> m b
ap =  liftM2 id

И liftM2 определяется очевидным образом:

liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) }

Это означает, что для любого функтора, который является Monad, а также Applicative, ожидается (по спецификации, поскольку это невозможно выполнить в коде), что Applicative будет работа слева направо, так что блок do в liftM2 выполняет то же самое, что и liftA2 f x y = f <$> x <*> y.

Из-за вышеприведенного, даже для экземпляров Applicative без соответствующего Monad, по соглашению эффекты обычно упорядочиваются также слева направо.

В более широком смысле, поскольку структура вычисления Applicative обязательно не зависит от "эффектов", вы обычно можете анализировать значение программы независимо от того, как эффекты Applicative упорядочиваются. Например, если экземпляр для [] был изменен на последовательность справа налево, любой код, использующий его, даст те же результаты, только с элементами списка в другом порядке.

Ответ 2

Да, порядок предопределен соглашением Monad-Applicative. Это легко увидеть: комбинатор (*>) должен соответствовать комбинатору (>>) в хорошо выполненном экземпляре Applicative для монады, и его определение:

a *> b = liftA2 (const id) a b

Другими словами, если b было выполнено до a, экземпляр Applicative будет плохо себя вести.

Изменить: как примечание: это явно не указано нигде, но вы можете найти много других подобных соответствий, таких как liftM2= liftA2 и т.д.

Ответ 3

Для IO Applicative это, безусловно, так. Но посмотрите асинхронный пакет для примера аппликативного, где в f <$> a <*> b эффекты a и b происходят параллельно.