haskell - Type inference of instance functions -


the problem

i want able create 2 data types: a , b , create 2 functions f:

  • f :: -> int -> int
  • f :: b -> string -> string -> string

the way can (so far know) use type classes , instances.

the problem is, not want explicit write f signatures - want type checker infer me. possible?

example code

{-# language flexibleinstances, functionaldependencies, undecidableinstances #-}  data = a{ax::int} deriving(show) data b = b{bx::int} deriving(show) data c = c{cx::int} deriving(show)  -- don't want explicit signature int->int -- love write:  -- instance func_f (a->b)  instance func_f (int->int)      f _ = i*2  -- don't want explicit signature string->string->string -- love write: -- instance func_f b (a->b->c)  instance func_f b (string->string->string)      f _ s1 s2 = "test"++s1++s2  -- don't want explicit signature a->a -- love write: -- instance func_f c (a->b)  instance func_f c (a->a)      f _ =  class func_f b | -> b      f :: -> b  f2 _ s1 s2 = "test"++s1++s2 -- here type inferencer automaticly recognizes signature  main :: io () main =      let          = 1         b = b 2         c = c 3         a_out = f 5         b_out = f b "a" "b"         c_out = c 6      print a_out     print b_out     print c_out 

explaination

i'm writing custom domain language compiler , i'm generating haskell code result. don't want final users of language write explicit types, want use haskells powerful type system infer as possible.

if write function f2 _ s1 s2 = "test"++s1++s2 not have explicit write signature - because compiler can infer it. can somehow ask compiler infer signatures of f in above example?

i love know every possible "hack" solve problem, if hack "ugly", because i'm generating haskell code , not have "pretty".

here's 1 way kind of works. there many more cases cover if fa fb have type variables in inferred types. in case following code have pattern match failures @ compile time.

{-# language flexibleinstances, functionaldependencies, templatehaskell #-}  import language.haskell.th  data = a{ax::int} deriving(show) data b = b{bx::int} deriving(show)  fa a{} = i*(2 :: int)  fb b{} s1 s2 = "test"++s1++s2  class func_f b | -> b      f :: -> b  let     getletter (appt (appt _ x) _) = x     getsnd (appt x y) = y     mkinst name0  =         (vari n ty _ _) <- reify name0         fmap (:[]) $ instanced (return [])             [t| func_f                     $(return $ getletter ty)                     $(return $ getsnd ty) |]             [vald (varp 'f) (normalb (vare name0)) []]      in fmap concat $ mapm mkinst ['fb, 'fa]   main :: io () main =      let          = 1         b = b 2         a_out = f 5         b_out = f b "a" "b"      print a_out     print b_out 

whether helps language you're compiling haskell question.


added hints

if type polymorphic, you'll see reify giving isn't covered example code above.

 > :set -xtemplatehaskell  > :m +ipprint language.haskell.th  > putstrln $(reify 'id >>= stringe . pshow) 

prints out describes (a->a):

vari ghc.base.id   (forallt [plaintv a_1627394484] []      (appt (appt arrowt (vart a_1627394484)) (vart a_1627394484)))   nothing   (fixity 9 infixl) 

with bit of work, split type in there cxtq , typeq instanced needs.

i don't know how sense makes generate (a->b) instead. go replacing type variables new unique ones, best done data.generics.everywherem because data type has many many constructors.

you'll still have issue invalid:

instance func_f (a -> b)    f _ = id 

this approach getting (a->b) can make program crash:

instance func_f (a -> b)    f _ = unsafecoerce id 

this approach lets instance chosen when types different, @ later point in ghc's execution can end failure if 'a' , 'b' can't same.

instance (a~b) => func_f (a->b)    f _ = unsafecoerce id 

Comments

Popular posts from this blog

php - Calling a template part from a post -

Firefox SVG shape not printing when it has stroke -

How to mention the localhost in android -