
On 10/27/12 9:06 PM, Brandon Simmons wrote:
On Sat, Oct 27, 2012 at 8:48 PM, Shachaf Ben-Kiki
wrote: To (1), it's probably worth mentioning the idiom of pre-applying readTChan and writeTChan to a channel to produce values of types "STM a" and "a -> STM ()", which gives you something pretty similar to read-only and write-only channels. It doesn't solve every problem, but for many things it's much simpler than introducing special-purpose types that only ever have one operation applied to them (similarly you could use values "STM (STM a)" with dupTChan/newBroadcastTChan, and so on).
Ah! I use that myself in a library because it let me create Functor and Contravariant instances for the read and write ends respectively, and I didn't require any additional operations beyond read and write.
It may be worth mentioning that for this use case there's some beauty in leaving it as one type and just giving it two type parameters, a la newTChan :: STM (TChan a a) writeTChan :: a -> TChan a b -> STM () readTChan :: TChan a b -> STM b -- aka contramap @(TChan _ c) precomposeTChan :: (a -> b) -> TChan b c -> TChan a c -- aka fmap @(TChan a _) postcomposeTChan :: (b -> c) -> TChan a b -> TChan a c since this highlights the fact that the two ends together form a profunctor, i.e. a hom-functor which is covariant in its output and contravariant in its input. Of course, even with this representation it's worthwhile to be able to abstract over each of the ends in order to preclude reading or writing in various parts of your program. -- Live well, ~wren