Send Beginners mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://www.haskell.org/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. Re:  Defining ExtensionClass (Maybe a) instance in xmonad.
      (Dmitriy Matrosov)
   2. Re:  Defining ExtensionClass (Maybe a) instance   in xmonad.
      (Brandon Allbery)
   3. Re:  Defining ExtensionClass (Maybe a) instance   in xmonad.
      (Thomas Bach)


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

Message: 1
Date: Tue, 20 Jan 2015 22:51:34 +0300
From: Dmitriy Matrosov <[email protected]>
To: [email protected]
Subject: Re: [Haskell-beginners] Defining ExtensionClass (Maybe a)
        instance in xmonad.
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8; format=flowed

  On 2015?01?19? 17:55, Brandon Allbery wrote:
  > ExtensionClass data is stored in the layout and therefore
  > requires those constraints. No, there is no magic to
  > cause non-persistent ExtensionClass data to be stored in
  > some other place different from where the rest of it is
  > stored.

Thanks for answer, but i don't understand why it should be
stored differently (i don't know how Typeable and
ExtensionClass works, so may be this is the reason): if i
define

     instance (ExtensionClass a) => ExtensionClass (Maybe a) where
        initialValue = Nothing
        extensionType = StateExtension

then there is no (Show a, Read a) constraint. It will come
up only, when i mention PersistentExtension in one of case
branches, but, on the other hand, may be i can avoid
pattern-matching on StateExtension constructor and somehow
use data constructor from (extensionType :: a ->
StateExtension) directly?  I'm already have (ExtensibleState
a) constraint, so does type a has Show and Read instances or
not, i think, this is correct (at least theoretically) to
define extensionType for (Maybe a) to use the same data
constructor.

  > I'm also wondering how much trouble you can get into by
  > conflicting with some other ExtensionClass that already
  > uses Maybe.

Well, i've just tried to restart xmobar properly, when i
reload xmonad. I've noticed, that xmobar restarts with
xmonad only, when it uses StdinReader (in template),
otherwise new (another) xmobar instance spawned.

I want to define generic way for restarting something,
spawned by xmonad.

 > {-# LANGUAGE    MultiParamTypeClasses
 >               , FunctionalDependencies
 >               , FlexibleInstances
 >               , FlexibleContexts
 >               , DeriveDataTypeable #-}
 >
 > import XMonad
 > import qualified XMonad.Util.ExtensibleState as XS
 > import System.Posix.Process
 > import System.IO
 > import System.Posix.IO
 > import System.Posix.Types

I may define a data type containing required start/stop
functions and depending on some identifier (ProcessID
actually):

 > data Restartable a = Restartable
 >                       { killP :: a -> X ()
 >                       , runP  :: X a
 >                       }

or i can define interface, which all identifiers should
support:

 > class RestartClass a where
 >   killP' :: a -> X ()
 >   runP'  :: X a

Then i may store (Maybe a) in extensible state and write
generic restart functions:

 > restartP :: (ExtensionClass (Maybe a)) => Restartable a -> X ()
 > restartP r    = do
 >   mp <- XS.get
 >   whenJust mp (killP r)
 >   p' <- runP r
 >   XS.put (Just p')
 >
 > restartP' :: (ExtensionClass (Maybe a), RestartClass a) => X a
 > restartP'     = do
 >   mp <- XS.get
 >   whenJust mp killP'
 >   p' <- runP'
 >   XS.put (Just p' `asTypeOf` mp)
 >   return p'

and, finally, i may define Restartable value and
RestartClass instance for xmobar, and define restart
function for xmobar:

 > newtype XmobarPID = XmobarPID ProcessID
 >   deriving (Show, Read, Typeable)
 >
 > newtype XmobarHandle = XmobarHandle (Maybe Handle)
 >   deriving (Typeable)
 >
 > instance ExtensionClass XmobarHandle where
 >     initialValue  = XmobarHandle Nothing
 >
 >
 > instance (Show a, Read a, Typeable a) => ExtensionClass (Maybe a) where
 >    initialValue   = Nothing
 >    extensionType  = PersistentExtension
 >
 >
 > -- For data type approach..
 > xmobarP :: Restartable XmobarPID
 > xmobarP   = Restartable killXmobar runXmobar
 >   where
 >     killXmobar :: XmobarPID -> X ()
 >     killXmobar (XmobarPID p)  = io $ spawn ("kill " ++ show p)
 >     runXmobar :: X XmobarPID
 >     runXmobar     = do
 >       (h, p) <- spawnPipe' ["/usr/bin/xmobar", "/home/sgf/.xmobarrc"]
 >       XS.put (XmobarHandle (Just h))
 >       return (XmobarPID p)
 >
 > restartXmobar :: X ()
 > restartXmobar     = restartP xmobarP
 >
 >
 > -- For type-class approach..
 > instance RestartClass XmobarPID where
 >   killP' (XmobarPID p) = io $ spawn ("kill " ++ show p)
 >   runP'                = do
 >       (h, p) <- spawnPipe' ["/usr/bin/xmobar", "/home/sgf/.xmobarrc"]
 >       XS.put (XmobarHandle (Just h))
 >       return (XmobarPID p)
 >
 > restartXmobar' :: X ()
 > restartXmobar'    = do
 >       p <- restartP'
 >       let _ = p `asTypeOf` XmobarPID undefined
 >       return ()
 >
 > -- Rewritten version from XMonad.Util.Run: do not run shell and return
 > -- ProcessID .
 > spawnPipe' :: [String] -> X (Handle, ProcessID)
 > spawnPipe' (x : xs) = io $ do
 >         (rd, wr) <- createPipe
 >         setFdOption wr CloseOnExec True
 >         h <- fdToHandle wr
 >         hSetBuffering h LineBuffering
 >         p <- xfork $ do
 >               _ <- dupTo rd stdInput
 >               executeFile x False xs Nothing
 >         closeFd rd
 >         return (h, p)

but here i can't reuse ExtensionClass (Maybe a) instance for
XmobarHandle, because Handle does not have Read instance and
can't have extensionType = PersistentExtension . So i've
added Maybe in XmobarHandle newtype.

Also, i may go the other way: add Maybe to XmobarPID value,
and then define ExtensionClass instance for XmobarPID. Then
i won't need ExtensionClass (Maybe a) instance.

 > newtype XmobarPID2 = XmobarPID2 (Maybe ProcessID)
 >   deriving (Typeable, Show, Read)
 >
 > instance ExtensionClass XmobarPID2 where
 >     initialValue  = XmobarPID2 Nothing
 >     extensionType = PersistentExtension
 >

In this case i need a way to convert value of some type into
Maybe:

 > class Lens a b | a -> b where
 >     view :: a -> b
 >     set  :: b -> a -> a
 >
 > instance Lens XmobarPID2 (Maybe XmobarPID) where
 >     view (XmobarPID2 x)           = fmap XmobarPID x
 >     set (Just (XmobarPID x)) _    = XmobarPID2 (Just x)
 >     set Nothing  z                = z

then restartP and restartP' should be adjusted to use
view/set from Lens class

 > -- Why ghc can't infer type a from b here? I.e. i need to return X a, not
 > -- X () as before. Is it because of functional dependency a -> b in Lens
 > -- definition ?
 > restartP2 :: (ExtensionClass a, Lens a (Maybe b)) => Restartable b -> X a
 > restartP2 r       = do
 >   mp <- XS.get
 >   whenJust (view mp) (killP r)
 >   p' <- runP r
 >   let mp' = set (Just p') mp
 >   XS.put mp'
 >   return mp'
 >
 > restartP2' :: (ExtensionClass a, Lens a (Maybe b), RestartClass b) => X a
 > restartP2'      = do
 >     mp <- XS.get
 >     whenJust (view mp) killP'
 >     p' <- runP'
 >     let mp' = set (Just p') mp
 >     XS.put mp'
 >     return mp'

but now restartXmobar with Restartable value will not be
that simple as before:

 > restartXmobar2 :: X ()
 > restartXmobar2    = do
 >   p <- restartP2 xmobarP
 >   let _ = p `asTypeOf` XmobarPID2 undefined
 >   return ()
 >
 > restartXmobar2' :: X ()
 > restartXmobar2'   = do
 >   p <- restartP2'
 >   let _ = p `asTypeOf` XmobarPID2 undefined
 >   return ()

So, i end up with two start/stop interface implementations:
     - Restartable data type
     - or RestartClass.

and with two extensible state implementations:
     - store identifier in Maybe
     - or add Maybe to identifier itself.

I don't like `asTypeOf` in restartXmobar variants . And i
don't like, that i can't reuse ExtensionClass (Maybe a)
instance for XmobarHandle ..

What implementation will be more idiomatic? Or, may be,
something completely different?




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

Message: 2
Date: Tue, 20 Jan 2015 15:14:24 -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] Defining ExtensionClass (Maybe a)
        instance        in xmonad.
Message-ID:
        <CAKFCL4X7vLNDtAx+_6fVfjhjZb6oM_=e71ryuqytqbyjvus...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

On Tue, Jan 20, 2015 at 2:51 PM, Dmitriy Matrosov <[email protected]> wrote:

> then there is no (Show a, Read a) constraint. It will come
> up only, when i mention PersistentExtension in one of case
> branches, but, on the other hand, may be i can avoid
>

That would be expected, I believe; if you mentioned it, it must apply to
the whole instance, not just one case branch. But I'm not quite clear on
what you are saying here.


> Well, i've just tried to restart xmobar properly, when i
> reload xmonad. I've noticed, that xmobar restarts with
> xmonad only, when it uses StdinReader (in template),
> otherwise new (another) xmobar instance spawned.
>

That is expected. You are expecting some kind of magic happening where we
track every pipe and forcibly terminate all of them, when all we are doing
is using normal POSIX semantics where pipes get closed automatically but
the process on the other side will only find out if it is reading from the
pipe (i.e. xmobar's StdinReader).

Doing the magic that you and others seem to expect would be in one way or
another very expensive --- either we make xmonad only work on one
particular OS family, or we accept that we can only spawn so many pipes
because of child process limits, or we have to make spawnPipe spawn a
backchannel to report the ultimate child *and* we must restrict what kinds
of things you can run on the other end so we can keep track and kill it.

(You probably want to consider the above with respect to your proposed
extension; the POSIX subprocess model has many dark corners. In particular,
remember that the child process "closest" to xmonad in a spawnPipe is a
shell, *not* the program you ran. And that shell has the same problem, so
killing it will not kill the xmobar it starts!)

-- 
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://www.haskell.org/pipermail/beginners/attachments/20150120/318b73a2/attachment-0001.html>

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

Message: 3
Date: Tue, 20 Jan 2015 23:17:49 +0100
From: Thomas Bach <[email protected]>
To: The Haskell-Beginners Mailing List - Discussion of primarily
        beginner-level topics related to Haskell <[email protected]>
Subject: Re: [Haskell-beginners] Defining ExtensionClass (Maybe a)
        instance        in xmonad.
Message-ID: <[email protected]>
Content-Type: text/plain; charset="utf-8"

Hi,

sadly, I don't have an answer to all your technical
question. Furthermore, I consider myself to be a Haskell starter so I
cannot answer your questions concerning idiomatic code properly. But
here is an answer anyway. :)

Dmitriy Matrosov <[email protected]> writes:

>  On 2015?01?19? 17:55, Brandon Allbery wrote:
> [?]
>
> I want to define generic way for restarting something,
> spawned by xmonad.
>
> [?]
>
> I may define a data type containing required start/stop
> functions and depending on some identifier (ProcessID
> actually):
>

I had kind of the same problem and went for the this option,
i.e. defining a data type. But I implemented this via a pid file which gets
saved on xmonad start up. This way these program can even survive a
restart of the XServer properly.

https://github.com/fuzzy-id/my-xmonad/blob/master/My/PidProg.hs
(see Config.hs in the same repo for an example of how I use them.)

However, I don't see the point in defining the data type to contain
start/stop functions. These will be the same for most of the
programs, won't they?

> [?]
>
> or i can define interface, which all identifiers should
> support:
>

This makes sense if you want to prepare to have a whole group of
different instances. We cannot know whether or not this is your case. If
you want to be prepared for this ? i.e. over-engineer the whole thing ?
I'd probably go this path.

Define a class which asks its instances to have a start/stop function
and so on. Then you can define an instance which xmobar and probably a
whole lot of other programs will nicely fit.

Hope this helps

     Thomas.


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

Subject: Digest Footer

_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners


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

End of Beginners Digest, Vol 79, Issue 23
*****************************************

Reply via email to