C'è un modo facile e veloce per scoprire la precedenza e l'associatività di una funzione in GHCI?Come scoprire la precedenza e l'associatività di una funzione in GHCI?
Ho trovato che un metodo semplice è quello di bruteforce che combina un operatore con un altro fino a ottenere un errore di analisi della precedenza (PPE). Ad esempio, per scoprire la precedenza/associatività di !!
, possiamo definire 10 diversi operatori di infix n
per 0 ≤ n < 10
:
>>> let infix 0 %; (%) = ($)
>>> undefined % undefined !! undefined
*** Exception: Prelude.undefined
>>> let infix 1 %; (%) = ($)
>>> undefined % undefined !! undefined
*** Exception: Prelude.undefined
[...]
>>> let infix 8 %; (%) = ($)
>>> undefined % undefined !! undefined
*** Exception: Prelude.undefined
>>> let infix 9 %; (%) = ($)
>>> undefined % undefined !! undefined
<interactive>:21:1:
Precedence parsing error
cannot mix `%' [infix 9] and `!!' [infixl 9] in the same infix expression
L'errore ti dice quello che i predences e fissità sono. Poiché le 10 funzioni definite sono non associative, non c'è possibilità di evitare un DPI quando i livelli di precedenza sono uguali. L'approccio ingenuo sarebbe stato quello di provare 10 funzioni di ogni associatività, dando un WCET di 20 (perché se si inizia sulla stessa associatività del bersaglio, il 10 con quell'associatività passerebbe, ma poi l'errore si verificherà una volta che si arriva a la precedenza della prossima associatività kth
, dove k
è la precedenza della funzione di destinazione).
Ma c'è un modo più veloce? I pensare in si può fare una bisezione per ottenere in media i passi di log (10). Ad esempio, se l'obiettivo era !!!
definito come !!
, ma con infixl 6
, è possibile creare un'espressione (:[]) % "AB" !!! 1
, dove %
è una delle stesse 10 funzioni fittizie. Se la precedenza di %
è troppo bassa per causare un DPI, l'espressione produrrà "B"
(poiché l'espressione verrà analizzata a (:[]) % ("AB" !!! 1)
), mentre se la precedenza è troppo alta, produrrà ⊥
(poiché l'espressione verrà analizzata a ((:[]) % "AB") !!! 1
). Esempio:
>>> let infixl 6 !!!; (!!!) = (!!)
>>> let infix 5 %; (%) = ($)
>>> (:[]) % "AB" !!! 1
"B"
>>> --too low
>>> let infix 7 %; (%) = ($)
>>> (:[]) % "AB" !!! 1
"*** Exception: Prelude.(!!): index too large
>>> --too high
>>> let infix 6 %; (%) = ($)
>>> (:[]) % "AB" !!! 1
<interactive>:10:1:
Precedence parsing error
cannot mix `%' [infix 6] and `!!!' [infixl 6] in the same infix expression
>>> --got it
Tuttavia, non sono sicuro di questo approccio.
- È necessario mantenere lo stato mentale di cui il numero di indovinare il prossimo, e di fare l'etc divisione nella tua testa (per carta/calcolatore sarebbe probabilmente più lento di solo facendo delle 10 fasi del metodo semplice)
- È completamente generale? Puoi sempre costruire un'espressione di test come questa?
- io non sono sicuro di poter sempre venire con un'espressione del genere più veloce di quello che posso solo fare il metodo semplice. In questo caso è stato davvero veloce, e io in realtà si avvicinò con il metodo di bisezione prima mi si avvicinò con il metodo semplice
- Se la preoccupazione precedente tiene valido, se esiste un modo del tutto generale, per generare automaticamente espressioni di questo genere?
È qualcuno a conoscenza di un metodo alternativo? Posso immaginare che ci possa essere un modo per farlo in un solo passaggio. Ma dopo un'ora, il meglio che ho potuto inventare è questo metodo di bisezione.
Puoi anche digitare solo, ad esempio, ': i +'. –