ho implementato trasduttori in Haskell come segue:trasduttori a Haskell e la restrizione monomorfismo
{-# LANGUAGE RankNTypes #-}
import Prelude hiding (foldr)
import Data.Foldable
type Reducer b a = a -> b -> b
type Transducer a b = forall t. Reducer t b -> Reducer t a
class Foldable c => Collection c where
insert :: a -> c a -> c a
empty :: c a
reduce :: Collection c => Transducer a b -> c a -> c b
reduce f = foldr (f insert) empty
mapping :: (a -> b) -> Transducer a b
mapping f g x = g (f x)
Ora voglio definire una funzione generica map
. Da qui si carica il codice sopra in GHCi:
Prelude> :load Transducer
[1 of 1] Compiling Main (Transducer.hs, interpreted)
Ok, modules loaded: Main.
*Main> let map = reduce . mapping
<interactive>:3:20:
Couldn't match type ‘Reducer t0 b1 -> Reducer t0 a1’
with ‘forall t. Reducer t b -> Reducer t a’
Expected type: (a1 -> b1) -> Transducer a b
Actual type: (a1 -> b1) -> Reducer t0 b1 -> Reducer t0 a1
Relevant bindings include
map :: (a1 -> b1) -> c a -> c b (bound at <interactive>:3:5)
In the second argument of ‘(.)’, namely ‘mapping’
In the expression: reduce . mapping
*Main> let map f = reduce (mapping f)
*Main> :t map
map :: Collection c => (a -> b) -> c a -> c b
Quindi non posso definire map = reduce . mapping
. Tuttavia, posso definire map f = reduce (mapping f)
.
Credo che questo problema sia causato dalla limitazione del monomorfismo. Mi piacerebbe davvero scrivere map = reduce . mapping
anziché map f = reduce (mapping f)
. Quindi, ho due domande:
- Che cosa sta causando questo problema? È davvero la restrizione del monomorfismo?
- Come posso risolvere questo problema?
Questo a causa dell'inferenza di tipo con ranghi più alti. La restrizione del monomorfismo non ha importanza qui. Nessuna correzione facile, suppongo, tranne l'aggiunta di un'annotazione di tipo o il passaggio a una definizione puntuale. – chi
Le annotazioni di tipo non aiutano: 'let map :: Collection c => (a -> b) -> c a -> c b; map f = reduce (mapping f) 'produce ancora lo stesso errore. –
L'errore di tipo indica esattamente qual è il problema. Il tipo di 'mapping' viene cambiato silenziosamente per spostare' forall' sul lato sinistro (prova ': t mapping'). Questa è una trasformazione valida (semantica-preservante), ma il tipografo si aspetta che il tipo "Trasduttore a b" sia corretto, non "Riduttore t a -> Riduttore t b" (che * potrebbe * essere di tipi distinti). Ma quando scrivi 'reduce (mapping f)', il typechecker vede l'applicazione di 'mapping f' deve avere tipo' forall t. Riduttore t b -> Riduttore t a', che è il tipo corretto per un argomento per 'ridurre'. – user2407038