So in my neuron project I have a pure function that looks at an ADT, does bunch of checks and returns something. But one of the constructors will have to use nextRandom :: IO UUID to create a random string, and that's an IO action. Everything else is pure code.
It would suck to make this entire function an IO action just for that one constructor.
I'm wondering if it would be unsuitable to sneak in polysemy just for this function. And then create a separate effect for the test (where I pass a predetermined "random" hash). Makes every thing else pure, and would give me an excuse to use and learn the newer effects system, but in a smaller part of the code.
Very close to main. In CLI argument handlers. But the function is small and you can tell what it does from its argument (without knowing the rest of the code base)
Well, here it is in its entirety (minus the IO action):
-- | Create a new zettel ID based on the given scheme without conflicting with-- the IDs of existing zettels.nextAvailableZettelID-- | Existing zettels::SetZettelID->IDScheme->EitherTextZettelIDnextAvailableZettelIDzs=\caseIDSchemeDateday->doletdayIndices=nonEmpty$sort$flipmapMaybe(Set.toListzs)$\caseZettelDateIDdx|d==day->Justx_->Nothingcaselast<$>dayIndicesofNothing->pure$ZettelDateIDday1Just99->throwError"Ran out of date ID indices"Justidx->pure$ZettelDateIDday(idx+1)IDSchemeHash->do-- TODO: IO!!!!!!!!!!!!!!!-- let h = T.take 8 $ UUID.toTextundefinedIDSchemeCustoms->runExcept$dozid<-fmapZettelCustomID$liftEither$first("Bad custom ID: "<>)$parsecustomIDParser"<next-id>"sifzid`Set.member`zsthenthrowError"An zettel with that ID already exists"elsepurezid
I would do manual UUID passing in this case, if you don't actively plan on having more effects
idk, seems like overkill for a single thing
even with some kind of effect system, I think it would still be better to have this function be effect-less, because all your other cases (the majority of your cases) would get "polluted" with more pures
Also adds --id=<custom> and --id-date.
Date ID is still the default .
And neuron new adds the creation date to the zettel metadata regardless of the ID scheme used.
For #151
So in my neuron project I have a pure function that looks at an ADT, does bunch of checks and returns something. But one of the constructors will have to use
nextRandom :: IO UUID
to create a random string, and that's an IO action. Everything else is pure code.It would suck to make this entire function an IO action just for that one constructor.
I'm wondering if it would be unsuitable to sneak in polysemy just for this function. And then create a separate effect for the test (where I pass a predetermined "random" hash). Makes every thing else pure, and would give me an excuse to use and learn the newer effects system, but in a smaller part of the code.
how "deep in the stack" is this function, i.e. from
main
?Very close to
main
. In CLI argument handlers. But the function is small and you can tell what it does from its argument (without knowing the rest of the code base)Well, here it is in its entirety (minus the IO action):
IDSchemeHash
is the constructor that will requireIO
.I would do manual
UUID
passing in this case, if you don't actively plan on having more effectsidk, seems like overkill for a single thing
even with some kind of effect system, I think it would still be better to have this function be effect-less, because all your other cases (the majority of your cases) would get "polluted" with more
pure
sWell, it is already in an error monad (Either or ExceptT)
and a
Reader
/Input
(overSet ZettelID
) I guess, if we're going to go looking for effects to insert(Member (Error ZettelIDConflict) r, Member UUID r) => m ZettelID
kind of looks niiiiceOr
Polysemy.Random
. I just want to produce hashes likecc982318
What's the benefit of using
Input
as opposed to passing it as a function argument?If you pass around the
Set
a lot it's worth itI guess
same as the
Either
/Except
- if you have a lot of stuff that could fail it's worth itOh right. The familiar config threading annoyance.
(In this case, though, it won't be passed further)
From the changelog,
Ah
polysemy-zoo has unwieldy deps
Painful deps, I'm going with GADTs
FWIW, here it is https://github.com/srid/neuron/pull/152/files#diff-73c560a0a454d2da4e37d64aaabb9b92
Separates out IO stuff in
genVal
, leaving the rest of mechanism in the pure function.^^ dependent type @TheMatten ?