Li-yao, thanks for the pointer. And my case is not really about ADTs, but to introspect the arguments an arbitrary Haskell function takes, including how many and what type each argument is, so as to extract proper values from a given ArgsPack, then call that Haskell function with those values as args it expects.

I'm not sure at a glance, that generics-eot has demonstrated how to obtain argument list with type info for a function, and will look into the details as I can.

Thanks with regards,
Compl


On 2020-09-10, at 23:08, Li-yao Xia <lysxia@gmail.com> wrote:

Hi Compl,

I couldn't tell what's generic (in the sense of GHC.Generics) about this example. A clearer example would be to give two applications with different algebraic data types, and to show how they consist of the same boilerplate, where the differences are only due to the differing numbers of fields and constructors.

As for tutorials on generics, a good starting point might be generics-eot. Its documentation comes with a series of tutorials:

https://generics-eot.readthedocs.io/en/stable/

Li-yao

On 9/10/2020 9:44 AM, YueCompl via Haskell-Cafe wrote:
Dear Cafe,
I'm tinkering with the idea for arbitrary Haskell functions to be easily called from scripting code, I see auto derive with GHC.Generics might be the most promising tool, but I'm lost after read https://wiki.haskell.org/GHC.Generics and hackage docs. I have no clue so far with how to start with it.
Specifically I want the section highlighted in blue get auto generated, within the following `runghc` ready example:
```
{-# LANGUAGEBangPatterns#-}
moduleMain where
importPrelude
importGHC.Generics
importData.Dynamic
-- * minimum data structures as interface with scripting code
typeAttrKey=String
dataAttrVal=NilValue
|IntValue!Integer
|StrValue!String
deriving(Eq,Ord,Typeable)
instanceShowAttrValwhere
show NilValue="nil"
show (IntValue!x)=show x
show (StrValue!x)=show x
dataArgsPack=ArgsPack{
positional'args::[AttrVal]
,keyword'args::[(AttrKey,AttrVal)]
}
instanceSemigroupArgsPackwhere
(ArgsPackp1 kw1)<>(ArgsPackp2 kw2)=ArgsPack(p1 ++p2)(kw1 ++kw2)
instanceMonoidArgsPackwhere
mempty =ArgsPack[][]
classCallableawhere
call::a->ArgsPack->(AttrVal->IO())->IO()
-- * functions to be callable from scripting code
newtypeAssert=Assert(
Expect->MaybeTarget->Message->IOMessage
)
typeExpect=AttrVal
typeTarget=AttrVal
typeMessage=String
instanceCallableAssertwhere
-- can this get auto-generated ? with https://wiki.haskell.org/GHC.Generics
call (Assert!assert)(ArgsPack!args !kwargs)!exit =do
(expect,target,message)<-parseApk
result <-assert expect target message
exit $StrValueresult
where
parseApk::IO(Expect,MaybeTarget,Message)
parseApk =goParse
(Left"missing arg: expect",Nothing,Left"missing arg: message")
args
kwargs
goParse (got'expect,got'target,got'message)[][]=casegot'expect of
Leftmsg ->error msg
Rightexpect ->casegot'message of
Leftmsg ->error msg
Rightmessage ->return (expect,got'target,message)
goParse (got'expect,got'target,got'message)args' ((name,val):kwargs')
=casename of
"expect"->casegot'expect of
Right{}->error "duplicate arg: expect"
Left{}->goParse (Rightval,got'target,got'message)args' kwargs'
"target"->casegot'target of
Just{}->error "duplicate arg: target"
Nothing->goParse (got'expect,Justval,got'message)args' kwargs'
"message"->casegot'message of
Right{}->error "duplicate arg: message"
Left{}->caseval of
StrValuemessage ->
goParse (got'expect,got'target,Rightmessage)args' kwargs'
_ ->error "bad arg type for: message"
_ ->error "unexpected keyword args"
goParse (got'expect,got'target,got'message)(val :args')[]=
casegot'expect of
Left{}->goParse (Rightval,got'target,got'message)args' []
Right{}->casegot'target of
Nothing->goParse (got'expect,Justval,got'message)args' []
Just{}->casegot'message of
Left{}->caseval of
StrValuemessage ->
goParse (got'expect,got'target,Rightmessage)args' []
_ ->error "bad arg type for: message"
Right{}->error "extranous positional args"
-- mockup & test out
main::IO()
main =
call
(Assertassert)
(ArgsPack[IntValue333,StrValue"as good will"]
[("target",IntValue333)]
)
$\result ->putStrLn $"Got result: "<>show result
-- | plain Haskell function meant to be easily called by scripting code
assert::Expect->MaybeTarget->Message->IOMessage
assert !expect !maybeTarget !message =casemaybeTarget of
Nothing->return $"* assertion not applicable: "<>message
Justtarget ->ifexpect ==target
thenreturn $"* assertion passed: "<>message
elseerror $"* assertion failed: "<>message
```
I tried to understand how
 * The compiler can provide a default generic implementation for
   |parseJSON
   <https://hackage.haskell.org/package/aeson-1.5.4.0/docs/Data-Aeson.html#v:parseJSON>|.
is implemented in [aeson](https://hackage.haskell.org/package/aeson) and it is overwhelming to me at the moment ...
Is there easier scaffold template for me to start with GHC.Generics? Or there're even better techniques to achieve my final goal?
Help please!
Best regards,
Compl
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.