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.  FFI Problems (Thomas Jakway)
   2. Re:  Using findIndex and then splitAt in  Data.List
      (Michael Orlitzky)
   3. Re:  Using findIndex and then splitAt in  Data.List (Geoffrey Bays)
   4. Re:  FFI Problems (Brandon Allbery)


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

Message: 1
Date: Sat, 28 Feb 2015 08:20:05 -0500
From: Thomas Jakway <[email protected]>
To: [email protected]
Subject: [Haskell-beginners] FFI Problems
Message-ID: <[email protected]>
Content-Type: text/plain; charset="utf-8"; Format="flowed"

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, channels = 12884901890, track = 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!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://mail.haskell.org/pipermail/beginners/attachments/20150228/2591d67e/attachment-0001.html>

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

Message: 2
Date: Sat, 28 Feb 2015 09:08:46 -0500
From: Michael Orlitzky <[email protected]>
To: [email protected]
Subject: Re: [Haskell-beginners] Using findIndex and then splitAt in
        Data.List
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8

On 02/27/2015 03:51 PM, Geoffrey Bays wrote:
> Hi.
> An elementary question here about two functions in Data.List:
>  how to use a value from findIndex which returns a Maybe Int,
> and then use that result in splitAt which takes a regular Int?

Once you understand why you can't feed a (Maybe Int) to a function that
takes an Int, throw it all away and use `splitOn` from the "split"
package instead =)

https://hackage.haskell.org/package/split-0.2.2/docs/Data-List-Split.html



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

Message: 3
Date: Sat, 28 Feb 2015 10:02:27 -0500
From: Geoffrey Bays <[email protected]>
To: The Haskell-Beginners Mailing List - Discussion of primarily
        beginner-level topics related to Haskell <[email protected]>
Subject: Re: [Haskell-beginners] Using findIndex and then splitAt in
        Data.List
Message-ID:
        <cad8ukx7cehtogkfht9sgo7c2pzjdmbmjj5nqhwie6vd6_ub...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

Michael:
Thanks, split on would work nicely.

I probably should have backed up in my reasoning process to say that my
real task is to replace a data item in a list with another altered data
item in the same position, or rather in FP, create a new list with the
altered item in the same place. And I need a predicate to find the name of
the item I want to replace.
Any thoughts?

Thanks,
Geoffrey
On Feb 28, 2015 9:08 AM, "Michael Orlitzky" <[email protected]> wrote:

> On 02/27/2015 03:51 PM, Geoffrey Bays wrote:
> > Hi.
> > An elementary question here about two functions in Data.List:
> >  how to use a value from findIndex which returns a Maybe Int,
> > and then use that result in splitAt which takes a regular Int?
>
> Once you understand why you can't feed a (Maybe Int) to a function that
> takes an Int, throw it all away and use `splitOn` from the "split"
> package instead =)
>
> https://hackage.haskell.org/package/split-0.2.2/docs/Data-List-Split.html
>
> _______________________________________________
> 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/20150228/9b930a59/attachment-0001.html>

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

Message: 4
Date: Sat, 28 Feb 2015 10:08:43 -0500
From: Brandon Allbery <[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:
        <CAKFCL4UQFP6DYd+OYYk-nHXKnRf88C=e3gvyuvbyceuxcxw...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

On Sat, Feb 28, 2015 at 8:20 AM, Thomas Jakway <[email protected]> wrote:

>  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 raw FFI is unfriendly, but also not really intended for direct use
except in very simple cases. You probably want to look into c2hs (or
gtk2hsc2hs which is a fork that supports more complex C headers) to
generate the FFI declarations, rather than try to manipulate structs
directly.

-- 
brandon s allbery kf8nh                               sine nomine associates
[email protected]                                  [email protected]
unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://mail.haskell.org/pipermail/beginners/attachments/20150228/a17e263a/attachment.html>

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

Subject: Digest Footer

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


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

End of Beginners Digest, Vol 80, Issue 71
*****************************************

Reply via email to