Penso che la vera risposta sia
- Se hai qualche tipo di colleghi su questo progetto, esegui questo da loro per ottenere la loro opinione.
- Se è solo per te, scegli quello che più ti piace.
Mentre Haskell supporta molto bene la programmazione point-free, la lingua e la comunità sono più o meno standardizzate attorno alla composizione da destra a sinistra basata sulla matematica con (.)
e ($)
. Sfortunatamente come hai notato, queste catene sono spesso meno leggibili rispetto alla controparte ruotata da sinistra a destra.
Ora è abbastanza facile definire le versioni capovolte degli operatori di cui sopra, ma la difficoltà è che non esiste una vera convenzione. Puoi utilizzare (>>>)
da Control.Arrow
. Ho anche visto (#)
in diagrams
o (&)
in Data.Functions
per flip ($)
. Ed è ovviamente solo un paio di righe per definire le tue versioni. Perché non c'è una sola risposta standard qui incontrerai un paio di problemi:
- Precedenza poco chiara.
(.)
e ($)
hanno una precedenza molto chiara e ben nota: rispettivamente più alta e più bassa. La precedenza di qualsiasi versione capovolta non sarà così familiare (i lettori del tuo codice non sapranno immediatamente come analizzare l'espressione).
- Onere cognitivo. C'è un piccolo ma preciso costo per l'uso di notazioni non familiari: i lettori devono ricordare a se stessi cosa stanno leggendo.
- La poca consuetudine. Mentre il codice che utilizza qualsiasi versione capovolta potrebbe essere totalmente valido e funzionante con codice Haskell, non sembrerà esattamente come il normale codice Haskell.
Mi imbatto in questi problemi in entrambi i casi. Nel primo caso, la compresenza di (>>>)
e (>>)
rende difficile l'analisi visiva della linea. Poiché (>>)
è più tranquillo, voglio raggruppare insieme le ultime due espressioni anche se ciò non è corretto. La seconda versione ha il problema che la lettura di una catena monadica da destra a sinistra è solo strana. Anche in questo caso non c'è nulla di sbagliato in entrambe le versioni, ma penso che rendano il tuo codice meno idiomatico per un piccolo guadagno.
Penso che la soluzione reale (oltre a prendere una macchina del tempo e riprogettare la libreria standard di Haskell) sia che ogni volta che si imbocca una catena (o in questo caso una catena di catene) che è difficile da leggere; piuttosto che cercare le indicazioni o qualsiasi cosa è meglio riscrivere / scomporre quell'espressione. Qui potrei suggerire
mainLoop :: Socket -> IO ()
mainLoop sock = do
contents <- accept sock
forkIO . handle . fst $ contents
mainLoop sock
O anche meglio
mainLoop sock = forever (accept sock >>= handleContents)
where
handleContents (h, _) = forkIO . handle $ h