Per cercare di semplificare questo problema ho definito queste funzioni di direzione:Esistono utili astrazioni per la sintassi del record di Haskell?
splitA :: (Arrow arr) => arr a b -> arr a (b,a)
splitA ar = ar &&& (arr (\a -> id a))
recordArrow
:: (Arrow arr)
=> (d -> r)
-> (d -> r -> d)
-> (r -> r)
-> arr d d
recordArrow g s f = splitA (arr g >>^ f) >>^ \(r,d) -> s d r
Che poi cerchiamo di fare a me una cosa del genere:
unarrow :: ((->) b c) -> (b -> c) -- unneeded as pointed out to me in the comments
unarrow g = g
data Testdata = Testdata { record1::Int,record2::Int,record3::Int }
testRecord = unarrow $
recordArrow record1 (\d r -> d { record1 = r }) id
>>> recordArrow record2 (\d r -> d { record2 = r }) id
>>> recordArrow record3 (\d r -> d { record3 = r }) id
Come si può vedere questo non fa buon uso di ASCIUTTO.
Spero ci possa essere una sorta di estensione del linguaggio che potrebbe aiutare a semplificare questo processo. In modo che il sopra potrebbe semplicemente essere riscritto come:
testRecord' = unarrow $
recordArrow' record1 id
>>> recordArrow' record2 id
>>> recordArrow' record3 id
Aggiornato per chiarezza: Per chiarire un po '. Sono consapevole che potrei fare qualcosa del genere:
foo d = d { record1 = id (record1 d), record2 = id (record2 d) }
Ma questo ignora qualsiasi ordine di esecuzione e qualsiasi stato. Supponiamo che la funzione di aggiornamento per record2
si basi sul valore aggiornato per record1
. In alternativa, potrei voler creare una freccia diversa simile a questa: arr d (d,x)
e quindi voglio creare un elenco di [x]
il cui ordine dipende dall'ordine di valutazione dei record.
Quello che ho trovato è che spesso desidero eseguire alcune funzionalità e successivamente aggiornare un record. Posso farlo facendo passare lo stato come questo
g :: d -> r -> d
foo d = let d' = d { record1 = (g d) (record1 d) } in d' { record2 = (g d') (record2 d') }
Ma penso freccia notazione è più ordinato, e potrei anche avere [arr d d]
e concatenare insieme in una sequenza. Inoltre se r
o d
sono Monade crea un codice più preciso. O se sono entrambi Monade, mi permetta di eseguire legature a strati senza dover usare un Monade Transformer. Nel caso di ST s x
, mi consente di inserire lo stato s
in modo ordinato.
Non sto cercando di risolvere un problema particolare. Sto solo cercando di trovare un metodo astratto per aggiornare una sintassi del record senza dover definire esplicitamente una sorta di "getter" e "setter".
Qui di seguito è stata risolta in senso comments-- Sidenote: Ho dovuto definire una funzione unarrow
per la conversione di una funzione (->) arrow torna a una funzione. Altrimenti se ho someArrow b
per una freccia arr b c
non riesco a ottenere il valore c
. Con la funzione unarrow
posso scrivere unarrow someArrow b
e funziona perfettamente. Mi sento come se dovessi fare qualcosa di sbagliato qui perché la mia definizione di unarrow è semplicemente unarrow g = g
.
La funzione 'unarrow' può essere rimosso se si dà' testRecord' una firma di tipo esplicito. C'è un problema con l'inferenza del tipo, non è possibile scoprire che 'testRecord' dovrebbe essere un tipo di funzione. – bmaderbacher
Sarebbe bello se potessi chiarire un po 'quello che non vorresti ottenere. Vuoi applicare le funzioni (id in questo caso) ai campi di un record, come ho ipotizzato per la mia risposta? – bmaderbacher
Grazie per il suggerimento su 'unarrow' @bmaderbacher. Stavo tormentando il mio cervello con il motivo per cui non potevo applicare la freccia in alcuni casi, definendo esplicitamente che è una funzione nella firma del tipo che ora sembra ovvia. – TheCriticalImperitive