I have a bunch of properties that need to know what my login name is on a host. I have a pure info property SPW.myAccountIs
to set this as host info. I have a function
getMyAcc :: Propellor User
which looks up this info or returns the default value 'spwhitton' if I didn't set a username on a host. It's easy to use getMyAcc
in writing my own properties, but I want to use it with existing properties. I'd like to write
withMyAcc :: IsProp p => (User -> p) -> p
so that for example I could say
& (withMyAcc $ \u -> User.accountFor u)
Even better, I'd like to be able to say
stdMachine = propertyListWithAcc "standard Debian setup" $ \u -> props
& User.accountFor u
& Sudo.enabledFor u
It seems like this ought to be possible; a property is something that does some stuff in the Propellor
monad and has a few other attributes, and those monadic actions can be conditional on some data not yet provided. However, I can't figure out how to do this with propellor's type system. If it's possible, I'd welcome hints.
--spwhitton
You can use
ensureProperty
to do this.The type of this will be somewhat more complex than the one you gave, but it should work.
Alas a description has to be provided to withMyAcc. It cannot reuse the description of
mkp
because to get a property that it can introspect for its description, a User has to be provided, and the User can only be determined by running Propellor (IO) action getMyAcc. You might be able to finesse this by using a monoidial value and get the description ofmkp mempty
.Or, you could do something like this to tie the knot. I don't know if this is a good idea (it might even
<<loop>>
), but it illustrates the core problem nicely; to get at the Info, we need a Host, but to get a Host, we need to already know its properties.Another, simpler approach that I often use in my config.hs:
You can also bundle up a bunch of properties that each need a User into a single combined
User -> Property DebianLike
GHC's inferred type is not something I can understand, and I suspect that it is far more general than it needs to be. In this sort of situation, are their strategies one can employ to write a sensible type signature? I think that the only thing I need to restrict is avoiding trying to ensure properties with info.
Could you expand a little on this suggestion, please? I want to be able to use unmodified core properties like
User.accountFor
, and that takes a non-monoidalUser
.This seems to work!
Maybe a
is a Monoid, so something along that line was what I was thinking.The complicated constraints there are inherited from the use of
ensureProperty
.A less general form of that is:
Unfortunately, the more general type doesn't seem to work:
yields