Send Beginners mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."


Today's Topics:

   1.  "Template Haskell and higher order meta  programming."
      (Song Zhang)
   2. Re:  FFI Problems (Thomas Jakway)


----------------------------------------------------------------------

Message: 1
Date: Tue, 3 Mar 2015 22:41:11 +0800
From: Song Zhang <[email protected]>
To: [email protected]
Subject: [Haskell-beginners] "Template Haskell and higher order meta
        programming."
Message-ID:
        <cacgmeon4-fufknhhptuttwydff71_98jrxf_mu65zytzlu0...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

I generally have 2 questions. I am writing some functions to derive
typeclass instances with a package called derive. I just want to get rid of
using Derivation type with a stupid reason. I want use just Name type.

How can I defined a function with type

derivings :: Name -> Name -> Q [Dec]

by using function derive :: Derivation -> Name -> Q [Dec]
so that user can just write derivings ''Eq ''D instead of derive makeEq ''D?

> {-# LANGUAGE TemplateHaskell #-}

> import Data.DeriveTH -- in derive package
> import Language.Haskell.TH
> import qualified Language.Haskell.TH.Syntax as S
> data D = D
> derivings :: Name -> String -> Q Exp
> derivings cla typ = do
>               let makeClassName = mkName $ "make" ++ nameBase cla
>               a <-  [| derive makeClassName (mkName typ) |]
>               return a

> instance S.Lift Name where
>         lift x = varE x

Main> :t derivings ''Eq "D"
derivings ''Eq "D" :: Q Exp

Main> :t $(derivings ''Eq "D")
$(derivings ''Eq "D") :: Q [Dec]

There is no problem to quote twice in other file in order to get the
declaration. Maybe it should called second order meta programming. But the
following has problems:

> derivings'' :: Name -> Name -> Q Exp
> derivings'' cla typ = do
>               let makeClassName = mkName $ "make" ++ nameBase cla
>               a <-  [| derive makeClassName typ |]
>               return a

Main> :t derivings''
derivings'' :: Name -> Name -> Q Exp

Main> :t derivings'' ''Eq ''D
derivings'' ''Eq ''D :: Q Exp

Main> :t $(derivings'' ''Eq ''D)
<interactive>:1:3:
    Illegal variable name: ?D?
    When splicing a TH expression:
      Data.DeriveTH.derive makeEq (Language.Haskell.TH.Syntax.mkName Main.D)
    In the splice: $(derivings'' ''Eq ''D)

In the first case I used String, it works. however, it is not workiing if I
use D with a Name type. Cannot figure it out.
My second question is that if my return type is Q [Exp] while the [Exp] can
be further expanded into [Dec]. How can I do it to expand [Exp] into [Dec]?
Do we have a function for $ in $(thcode_with_Q_Exp) so that I do not need
to splice each Exp value?

Best wishes
Song
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://mail.haskell.org/pipermail/beginners/attachments/20150303/2297b363/attachment-0001.html>

------------------------------

Message: 2
Date: Tue, 03 Mar 2015 14:27:08 -0500
From: Thomas Jakway <[email protected]>
To: The Haskell-Beginners Mailing List - Discussion of primarily
        beginner-level topics related to Haskell <[email protected]>
Subject: Re: [Haskell-beginners] FFI Problems
Message-ID: <[email protected]>
Content-Type: text/plain; charset="windows-1252"; Format="flowed"

Thanks very much!  This helped a lot (and you were right on #2... I 
really should have caught that).

On 3/2/15 10:20 AM, Sylvain Henry wrote:
> Hi,
>
> 1) You have a copy-paste error on the following line (s/bitrate/track)
>  track <- ((#peek struct music_metadata, bitrate) a) :: IO Int
>
> 2) By looking at the values you get in hexadecimal, you are reading 
> 64bits values when your C struct contains 32 bits values. If you use: 
> peek ... :: IO Int32, it should be ok.
>
> 3) From a style point of view, you could use Applicative operators 
> (from Control.Applicative) to avoid temporary names:
> peek a = MusicMetaData
>         <$> liftM constantToCodec $ (((#peek struct music_metadata, 
> codec) a) :: IO Int32)
>         <*> fmap fromIntegral (((#peek struct music_metadata, length) 
> a) :: IO Int32)
>         <*> fmap fromIntegral (((#peek struct music_metadata, bitrate) 
> a) :: IO Int32)
>         <*> fmap fromIntegral (((#peek struct music_metadata, 
> channels) a) :: IO Int32)
>         <*> fmap fromIntegral (((#peek struct music_metadata, track) 
> a) :: IO Int32)
>         <*> (peekCString =<< (#peek struct music_metadata, title) a)
>         ...
>
> 4) In your constantToCodec function, you don't need the temporary 
> names for all the constants.
>
> Best regards,
> Sylvain
>
> PS : recently I have been working on rewriting the FFI page on the 
> wiki to make it more beginner-friendly ;-). It is not totally finished 
> but I'm open to any comment. 
> https://www.haskell.org/wiki/Foreign_Function_Interface
>
> 2015-02-28 14:20 GMT+01:00 Thomas Jakway <[email protected] 
> <mailto:[email protected]>>:
>
>     I'm very new to Haskell and am trying to write a "real" program to
>     motivate myself to learn it better (so far I've only gotten
>     through Project Euler problems after reading LYAH and most of
>     RWH).  I'm using Taglib (https://github.com/taglib/taglib) to read
>     the metadata from a music file and print it.  I have a struct
>     C-side (with C linkage) serving as the bridge between Taglib's C++
>     and Haskell's FFI.  A small demo program (compiled with gcc and
>     linked against the C++ object files) gives the correct results,
>     but Haskell is weirdly only getting /some /of it right.
>     Specifically, the C string fields are working but ints are not.
>
>     The output from the C demo (what Haskell should be printing):
>
>     music_metadata
>     title: It's My Life,    artist: Bon Jovi,    album: Bon Jovi
>     Greatest Hits - The Ultimate Collection
>     comment: ,    genre: Rock,    track: 3,
>     length: 224,    bitrate: 256,    channels: 2,
>     codec: 768
>
>     The output from Haskell:
>
>     MusicMetadata {codec = UNKNOWN, length = 1099511628000, bitrate =
>     8589934848 <tel:8589934848>, channels = 12884901890, track =
>     8589934848 <tel:8589934848>, title = "It's My Life", artist = "Bon
>     Jovi", album = "Bon Jovi Greatest Hits - The Ultimate Collection",
>     comment = "", genre = "Rock"}
>
>     I would have expected it to work or not work at all, but did not
>     anticipate getting only some of it right.
>
>     I was going to include snippets from my hsc file but given how new
>     I am to Haskell I don't trust myself to assume where the problem
>     is, so sorry if this is way too long:
>
>     {-# LANGUAGE CPP, ForeignFunctionInterface #-}
>
>     module MusicReader
>     ( Codec,
>       MusicMetadata,
>       readMusicMetadata
>     ) where
>
>     import Control.Monad
>     import Foreign
>     import Foreign.C.Types
>     import Foreign.C.String
>     import System.IO.Unsafe as Unsafe
>
>     #include "CodecDefines.h"
>     #include "MusicReader.h"
>
>     constantToCodec code
>                         | code == mp3 = MP3
>                         | code == flac = FLAC
>                         | code == ogg = OGG_VORBIS
>                         | code == mp4 = MP4
>                         | code == mpeg = MPEG
>                         | code == none = NONE
>                         | code == unknown = UNKNOWN
>                         | otherwise = UNKNOWN
>                            where mp3 = #const MP3_CODEC
>                                  flac = #const FLAC_CODEC
>                                  ogg = #const OGG_VORBIS_CODEC
>                                  mp4 = #const MP4_CODEC
>                                  mpeg = #const MPEG_CODEC
>                                  none = #const NO_EXTENSION
>                                  unknown = #const UNKNOWN_EXTENSION
>
>     data Codec = MP3 | FLAC | OGG_VORBIS | MP4 | MPEG | NONE | UNKNOWN
>     deriving (Show)
>
>     data MusicMetadata = MusicMetadata { codec :: Codec,
>                           length :: Int,
>                           bitrate :: Int,
>                           channels :: Int,
>                           track :: Int,
>                           title :: String,
>                           artist :: String,
>                           album :: String,
>                           comment :: String,
>                           genre :: String } deriving (Show)
>
>     instance Storable MusicMetadata where
>         sizeOf _ = (#size struct music_metadata)
>         alignment _ = alignment (undefined::CDouble)
>         peek a = do
>             codec <- liftM constantToCodec $ (((#peek struct
>     music_metadata, codec) a) :: IO Int)
>             length <- ((#peek struct music_metadata, length) a) :: IO Int
>             bitrate <- ((#peek struct music_metadata, bitrate) a) ::
>     IO Int
>             channels <- ((#peek struct music_metadata, channels) a) ::
>     IO Int
>             track <- ((#peek struct music_metadata, bitrate) a) :: IO Int
>             title <-  ((#peek struct music_metadata, title) a) :: IO
>     CString
>             artist <- ((#peek struct music_metadata, artist) a) :: IO
>     CString
>             album <- ((#peek struct music_metadata, album) a) :: IO
>     CString
>             comment <- ((#peek struct music_metadata, comment) a) ::
>     IO CString
>             genre <- ((#peek struct music_metadata, genre) a) :: IO
>     CString
>             --FIXME: find replacement for temporary names
>             marshalledTitle <- peekCString title
>             marshalledArtist <- peekCString artist
>             marshalledAlbum <- peekCString album
>             marshalledComment <- peekCString comment
>             marshalledGenre <- peekCString genre
>             return (MusicMetadata codec length bitrate channels track
>     marshalledTitle marshalledArtist marshalledAlbum marshalledComment
>     marshalledGenre)
>         poke a = undefined
>
>     --This is the "primitive" FFI call--calls the C function and gets
>     a pointer
>     --in return
>     --TODO: write a higher level function this module should export
>     that calls
>     --primReadMusicMetadata and converts the C Pointer into the
>     Haskell data
>     --MusicMetadata
>     foreign import ccall unsafe "read_metadata" primReadMusicMetadata
>     :: CString -> IO (Ptr MusicMetadata)
>
>     --convert the Haskell string to a CString, call into the FFI then
>     --dereference the resulting pointer
>     readMusicMetadata a = join $ withCString a $ \cs -> ((liftM peek)
>     $ primReadMusicMetadata cs)
>
>
>
>     Here's the struct in MusicReader.h (in an extern C block):
>         struct music_metadata
>         {
>             int codec;
>             int length,
>                     bitrate,
>                     channels;
>             int track;
>             char *title,
>                  *artist,
>                  *album,
>                  *comment,
>                  *genre;
>         };
>
>
>     with the corresponding call:
>         struct music_metadata* read_metadata(char*);
>
>
>     I've tried playing around with the alignment but it didn't do
>     anything.  I also tried declaring the struct's fields as int32_t
>     which also did nothing.
>
>     The C demo in question is a very simple:
>
>     #include <stdio.h>
>     #include "MusicReader.h"
>
>     #define FILENAME "Its_My_Life.m4a"
>
>     int main()
>     {
>         struct music_metadata* metadata = read_metadata(FILENAME);
>         printf("music_metadata\ntitle: %s,\tartist: %s,\talbum: %s\n",
>                 metadata->title, metadata->artist, metadata->album);
>         printf("comment: %s,\tgenre: %s,\ttrack: %d,\n",
>                 metadata->comment, metadata->genre, metadata->track);
>         printf("length: %d,\tbitrate: %d,\tchannels: %d,\n",
>                 metadata->length, metadata->bitrate, metadata->channels);
>         printf("codec: %d\n");
>
>     }
>
>     It just reads the metadata into the struct and prints the fields.
>
>     I've gotten the impression of the Haskell FFI being very
>     beginner-unfriendly, which isn't surprising but still
>     disappointing because it would be a great opportunity to replace
>     some projects with Haskell.
>
>     Any help is appreciated, including general feedback on my code!
>
>     _______________________________________________
>     Beginners mailing list
>     [email protected] <mailto:[email protected]>
>     http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
>
>
>
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://mail.haskell.org/pipermail/beginners/attachments/20150303/5b0e0d62/attachment.html>

------------------------------

Subject: Digest Footer

_______________________________________________
Beginners mailing list
[email protected]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


------------------------------

End of Beginners Digest, Vol 81, Issue 12
*****************************************

Reply via email to