haskell -- is -ddump-simpl the best way to get a concrete type?

495 views Asked by At

I had previously written a function that seems to work, but unfortunately I didn't write the code very nicely, and now have to figure it out again [that I'm modifying the monad transformer stack I'm working with].

run_astvn ::
    LowerMonadT (StateT LowerSketchData Identity) β
    -> Seq SketchAST
run_astvn x = get_ast2 $ runIdentity $
    runStateT (runStateT (runStateT x empty) empty)
        (LowerSketchData Set.empty)
    where get_ast2 = snd . fst

I want to get the concrete type of get_ast2. I seem to be able to add the flag -ddump-simpl and grep through my terminal output until I find, (cleaned up a little)

(((β, Seq SketchAST), Seq SketchAST), LowerSketchData) -> Seq SketchAST

(Sorry this is likely nonsense to everyone else, but the point is it is useful for me.) Is there a faster / more convenient way to do this? In case it's not obvious, what I mean by "concrete" in this case is that the above type is useful; knowing the type of snd . fst is not :).

2

There are 2 answers

1
Daniel Wagner On BEST ANSWER

There's two ways I know of to do this currently, and they're both sort of hacks. The first is to use implicit parameters:

{-# LANGUAGE ImplicitParams #-}
import Control.Monad.State
import Control.Monad.Identity
import Data.Sequence
import qualified Data.Set as Set

data LowerSketchData = LowerSketchData (Set.Set Int)
type LowerMonadT m = StateT (Seq SketchAST) (StateT (Seq SketchAST) m)
data SketchAST = SketchAST

--run_astvn ::
--    LowerMonadT (StateT LowerSketchData Identity) β
--    -> Seq SketchAST
run_astvn x = ?get_ast2 $ runIdentity $
    runStateT (runStateT (runStateT x empty) empty)
        (LowerSketchData Set.empty)
--    where get_ast2 = snd . fst

Then, in ghci:

*Main> :t run_astvn
run_astvn
  :: (?get_ast2::(((a, Seq a1), Seq a2), LowerSketchData) -> t) =>
     StateT
       (Seq a1) (StateT (Seq a2) (StateT LowerSketchData Identity)) a
     -> t

The other way is to give an intentionally wrong type signature and check how the compiler complains.

import Control.Monad.State
import Control.Monad.Identity
import Data.Sequence
import qualified Data.Set as Set

data LowerSketchData = LowerSketchData (Set.Set Int)
type LowerMonadT m = StateT (Seq SketchAST) (StateT (Seq SketchAST) m)
data SketchAST = SketchAST

run_astvn ::
    LowerMonadT (StateT LowerSketchData Identity) β
    -> Seq SketchAST
run_astvn x = get_ast2 $ runIdentity $
    runStateT (runStateT (runStateT x empty) empty)
        (LowerSketchData Set.empty)
--    where get_ast2 = snd . fst
    where get_ast2 :: (); get_ast2 = undefined

This gives the error:

test.hs:13:19:
    The first argument of ($) takes one argument,
    but its type `()' has none
    In the expression:
      <snip>

Changing the wrong type to () -> ():

test.hs:13:30:
    Couldn't match expected type `()'
                with actual type `(((β, Seq SketchAST), Seq SketchAST),
                                   LowerSketchData)'
    In the second argument of `($)', namely
      <snip>

So now we know the type should look like (((β, Seq SketchAST), Seq SketchAST), LowerSketchData) -> (). One last iteration gets rid of the final (), because the compiler complains that:

test.hs:13:19:
    Couldn't match expected type `Seq SketchAST' with actual type `()'
    In the expression:
      <snip>

...so the other () should be Seq SketchAST.

0
Daniel Fischer On

Lie to the compiler. Add a wrong type signature, then it should reply with 'Couldn't match wrong type with real type' or whatever the exact message currently is.