Polysemy: Input

Whenever you might have varying strategies to fetch some data, you might want to use Input:

data Input i m a where
  Input :: Input i m i

it comes with three interpreters:

  • runInputConst to provide an unvarying value
runInputConst :: i -> Sem (Input i ': r) a -> Sem r a
runInputConst c = interpret $ \case
  Input -> pure c

usable as:

runInputConst @String "Hello, world!" $ input >>= embed . putStrLn
  • runInputList which aims to give a constant list of values one by one
runInputList ::
  [i] ->
  Sem (Input (Maybe i) ': r) a ->
  Sem r a
runInputList is =
  evalState is
    . reinterpret
      ( \case
          Input -> do
            s <- gets uncons
            for_ s $ put . snd
            pure $ fst <$> s
      )

usable as:

    runInputList @Char "Hello" $ whileJust (input @(Maybe Char)) $ embed . print
  • runInputSem to dynamically provide values (which should have been used instead of View in a previous log)
runInputSem :: forall i r a. Sem r i -> Sem (Input i ': r) a -> Sem r a
runInputSem m = interpret $ \case
  Input -> m

usable as:

message <- embed $ newMVar @String "Hello, world!"
runInputSem (embed $ tryTakeMVar message) $ whileJust (input @(Maybe String)) $ embed . putStrLn

See the full the code here.