Haskell: Reading from FS to "dynamically" create widgets in taffybar - haskell

I'm trying to use taffybar as my status bar (uses Dyre framework so configuration is code). It has a widget that can show network interface statistics. In the default configuration this widget requires a String at compile time. I want it to create a widget per (non-loopback) interface dynamically instead.
This is what I have so far:
listNetworkDevices :: IO [String]
listNetworkDevices = fmap (map takeBaseName) $ getDirectoryContents "/sys/class/net/"
filterOutLoopback :: [String] -> [String]
filterOutLoopback = filter (\y -> not (elem y ["", ".", "lo"]))
netDevList :: IO [String]
netDevList = fmap filterOutLoopback listNetworkDevices
...
let nets = fmap (fmap (netMonitorNew 1)) netDevList
...
defaultTaffybar defaultTaffybarConfig {
...
endWidgets = [ tray, clock, mem, cpu] ++ nets ++ [ bat ]
}
At this point I'm down to the following compiler error:
Couldn't match expected type ‘[IO gtk-0.14.2:Graphics.UI.Gtk.Types.Widget]’
with actual type ‘IO [IO gtk-0.14.2:Graphics.UI.Gtk.Types.Widget]’
Overall this the error makes sense since I'm making an IO Widget out of every String. So IO [String] turns into IO [IO Widget].
What I don't understand is how to avoid doing this. Clearly I must have gone wrong at some point but I can't see where. I'm not even sure how to put the issue in words. I would be glad for any pointers!
Relevant material:
endWidgets docs: https://hackage.haskell.org/package/taffybar-0.4.6/docs/System-Taffybar.html#v:endWidgets
netMonitorNew docs: https://hackage.haskell.org/package/taffybar-0.4.6/docs/System-Taffybar-NetMonitor.html#v:netMonitorNew
Source on github: https://github.com/travitch/taffybar/tree/master/src/System/Taffybar
Edit: complete listing:
import System.Taffybar
import System.Taffybar.Systray
import System.Taffybar.Pager
import System.Taffybar.TaffyPager
import System.Taffybar.SimpleClock
import System.Taffybar.Battery
import System.Taffybar.NetMonitor
import System.Taffybar.Weather
import System.Taffybar.Widgets.PollingBar
import System.Taffybar.Widgets.PollingGraph
import System.Information.Memory
import System.Information.CPU
import System.Directory ( getDirectoryContents )
import System.FilePath ( takeBaseName )
import Control.Monad
memCallback = do
mi <- parseMeminfo
return [memoryUsedRatio mi]
cpuCallback = do
(userLoad, systemLoad, totalLoad) <- cpuLoad
return [totalLoad, systemLoad]
listNetworkDevices :: IO [String]
listNetworkDevices = fmap (map takeBaseName) $ getDirectoryContents "/sys/class/net/"
filterOutLoopback :: [String] -> [String]
filterOutLoopback = filter (\y -> not (elem y ["", ".", "lo"]))
netDevList :: IO [String]
netDevList = fmap filterOutLoopback listNetworkDevices
myPagerConfig = defaultPagerConfig {}
main = do
let memCfg = defaultGraphConfig { graphDataColors = [(1, 0, 0, 1)] }
cpuCfg = defaultGraphConfig { graphDataColors = [ (0, 1, 0, 1)
, (1, 0, 1, 0.5)
]
}
clock = textClockNew Nothing "<span fgcolor='orange'>%a %b %d %H:%M</span>" 1
pager = taffyPagerNew myPagerConfig
mem = pollingGraphNew memCfg 1 memCallback
cpu = pollingGraphNew cpuCfg 1 cpuCallback
bat = textBatteryNew "$percentage$% $time$" 1
tray = systrayNew
--nets = [ netMonitorNew 1 "wlp0s2" ]
nets = fmap (fmap (netMonitorNew 1)) netDevList
defaultTaffybar defaultTaffybarConfig { startWidgets = [ pager ]
, endWidgets = [ tray, clock, mem, cpu] ++ nets ++ [ bat ]
}
Edit: Error message:
.config/taffybar/taffybar.hs:
Couldn't match expected type ‘[IO
gtk-0.14.2:Graphics.UI.Gtk.Types.Widget]’
with actual type ‘IO [IO gtk-0.14.2:Graphics.UI.Gtk.Types.Widget]’
In the first argument of ‘(++)’, namely ‘nets’
In the second argument of ‘(++)’, namely ‘nets ++ [bat]’

I haven't tested this as I usually do, since I don't have taffybar installed on this machine, but I suspect the following small change should help you make progress:
main = do
let memCfg = defaultGraphConfig { graphDataColors = [(1, 0, 0, 1)] }
cpuCfg = defaultGraphConfig { graphDataColors = [ (0, 1, 0, 1)
, (1, 0, 1, 0.5)
]
}
clock = textClockNew Nothing "<span fgcolor='orange'>%a %b %d %H:%M</span>" 1
pager = taffyPagerNew myPagerConfig
mem = pollingGraphNew memCfg 1 memCallback
cpu = pollingGraphNew cpuCfg 1 cpuCallback
bat = textBatteryNew "$percentage$% $time$" 1
tray = systrayNew
-- this line is the only one that changed
nets <- fmap (fmap (netMonitorNew 1)) netDevList
defaultTaffybar defaultTaffybarConfig { startWidgets = [ pager ]
, endWidgets = [ tray, clock, mem, cpu] ++ nets ++ [ bat ]
}
There may be other problems, but this should address the one described in the question.
There are plenty of stylistic changes that could/should be made as well, of course; for example, I think I would probably write the last two lines this way instead:
nets <- netDevList
defaultTaffybar ... { ..., endWidgets = ... ++ map netMonitorNew nets ++ ... }

Related

How can I reduce the criterion benchmark time?

I'm trying to use the criterion library to do some benchmarking.
I've tried a simple example:
module Main where
import Criterion.Types
import Criterion.Main
myConfig :: Config
myConfig = defaultConfig {
resamples = 1
}
main :: IO ()
main = do
let f = (\x -> bench (show x) $ whnf xyz x)
defaultMainWith myConfig [
bgroup "fib" [
env (pure 5) f
]
]
xyz :: Int -> [Double]
xyz 0 = []
xyz x = case x of
100 -> [sin $ fromIntegral x] ++ (xyz (x - 1))
_ -> [sin $ fromIntegral (2 * x)] ++ (xyz (x - 1))
However this seems to take a few seconds to complete, I'd assume it'd complete significantly quicker?
Why is it taking so long? How can I reduce the duration (even at the cost of inaccuracy)?
Set the timeLimit field of Config. For example:
myConfig :: Config
myConfig = defaultConfig {
resamples = 1, timeLimit = 1
}

EncodeException "The serialized GlobalReference has type PointerType"

As a CS student, I am asked to write a compiler in a functional language with LLVM. I chose Haskell, despite the fact that I am very new to it and that I don't understand everything in source code examples, that's why my code may looks disgracious.
Before really beginning my project, I wanted to play a little bit with LLVM's Haskell bindings and make a function that call another which returns the difference between the two integers passed as parameters.
When running the code, I have the following exception :
EncodeException "The serialized GlobalReference has type PointerType {pointerReferent = FunctionType {resultType = IntegerType {typeBits = 32}, argumentTypes = [IntegerType {typeBits = 32},IntegerType {typeBits = 32}], isVarArg = False}, pointerAddrSpace = AddrSpace 0} but should have type IntegerType {typeBits = 32}
And I really don't understand what is wrong with my code.
Here is my complete source code, thanks for your help.
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Monad.Except
-- Pretty Printer
import LLVM.Pretty (ppllvm, ppll)
import LLVM.Module
import LLVM.Context
import LLVM.Module
-- AST
import LLVM.AST
import qualified LLVM.AST as AST
import LLVM.AST.Global
import LLVM.AST.CallingConvention
import LLVM.AST.Constant as Kokai
import qualified Data.ByteString.Char8 as B
int :: Type
int = IntegerType 32
defAdd :: Definition
defAdd = GlobalDefinition functionDefaults
{ name = Name "subbing"
, parameters =
( [ Parameter int (Name "a") []
, Parameter int (Name "b") [] ]
, False )
, returnType = int
, basicBlocks = [block]
}
where
block :: BasicBlock
block = BasicBlock
(Name "entry")
[ Name "result" :=
AST.Sub False
False
(LocalReference int (Name "a"))
(LocalReference int (Name "b"))
[] ]
(Do $ Ret (Just (LocalReference int (Name "result"))) [])
foo :: Definition
foo = GlobalDefinition functionDefaults
{ name = Name "random_func"
, parameters = ([], False)
, returnType = int
, basicBlocks = [calli]
}
where
calli :: BasicBlock
calli = BasicBlock
(Name "entry")
[Name "res" :=
Call
Nothing
C
[]
(Right $ ConstantOperand $ GlobalReference int "subbing")
[(ConstantOperand $ Int 32 10, []),
(ConstantOperand $ Int 32 7, [])]
[]
[]
]
(Do $ Ret (Just (ConstantOperand $ Int 32 10)) [])
--(Do $ Ret (Just (LocalReference int (Name "res"))) [])
astModule :: AST.Module
astModule = defaultModule
{ moduleName = "my-module"
, moduleDefinitions = [defAdd, foo]
}
nimoft :: IO B.ByteString
nimoft = withContext $ \context ->
withModuleFromAST context astModule $ \m -> do
llstr <- moduleLLVMAssembly m
B.putStrLn llstr
return llstr
main :: IO ()
main = do
lol <- nimoft
Prelude.putStrLn "hello"
Just found the error, I changed the line of the call with :
(Right $ ConstantOperand $ GlobalReference (PointerType (FunctionType int [int, int] False) (A.AddrSpace 0)) (Name "subbing"))

Updating visibility of dynamically created content

Duplicating this from github as per #HeinrichApfelmus's suggestion:
This may be just a usage error on my part, but I am noticing a strange phenomenon when trying to set up conditional visibility/layout for dynamically created UI elements (in WX of course). As somewhat of a toy-example, I tried to create a widget that created StaticText elements on the fly and allowed the user to "browse" through these elements through '<' '>' buttons.
The problem I am noting is that all labels are invisible until a new one is created, at which point the current widget in focus becomes visible. Whether this is a bug or just a paradigm I am misusing, or a subtlety with reactive frameworks, I am unsure as to how to resolve this. Here is the code I have at this point, which exhibits the problem:
{-# LANGUAGE RecursiveDo #-}
module Test.Adder where
import Reactive.Banana
import Reactive.Banana.WX
import Graphics.UI.WX.Attributes
import Graphics.UI.WX hiding (Event, newEvent, empty, Identity)
import Graphics.UI.WXCore hiding (Event, Timer, empty, Identity, newEvent)
import Graphics.UI.WXCore.Frame
-- | Combine Unit-Events
anyEvent :: [Event ()] -> Event ()
anyEvent = foldl1 (unionWith (\_ _ -> ()))
-- | Unsugared if-then-else function
if_ :: Bool -> a -> a -> a
if_ True x _ = x
if_ False _ y = y
-- | Apply a function to the value at an index, or return a default value
-- if the index is out of range
(!?) :: (a -> b) -> b -> Int -> ([a] -> b)
(f!? ~y) n xs
| n < 0 = y
| otherwise = case drop n xs of
x:_ -> f x
[] -> y
main :: IO ()
main = start test
create :: Window w -> Int -> Behavior Int -> Event Int -> Event () -> MomentIO (StaticText ())
create t i bi ei eRef = do
let tx = replicate i '\t' ++ show i
x <- liftIO $ staticText t [ text := tx ]
let beq = (==i) <$> bi
let eMe = filterE (==i) ei
sink x [ visible :== beq ]
reactimate (refresh x <$ anyEvent [ eRef, () <$ eMe ])
return x
test :: IO ()
test = do
f <- frame [text := "Test"]
add <- button f [ text := "+" ]
prv <- button f [ text := "<" ]
cur <- staticText f []
nxt <- button f [ text := ">" ]
tab <- panel f [ clientSize := sz 200 300 ]
deb <- staticText f []
ref <- button f [ text := "refresh" ]
let networkDescription :: MomentIO ()
networkDescription = mdo
eAdd <- event0 add command
eRef <- event0 ref command
let bNotFirst = (>0) <$> bCur
bNotLast = (<) <$> bCur <*> bNext
sink prv [ enabled :== bNotFirst ]
sink cur [ text :== show <$> bCur ]
sink nxt [ enabled :== bNotLast ]
ePrev <- event0 prv command
eNext <- event0 nxt command
let eDelta :: Enum n => Event (n -> n)
eDelta = unions [ pred <$ whenE bNotFirst ePrev
, succ <$ whenE bNotLast eNext ]
eChange = flip ($) <$> bCur <#> eDelta
bCur <- stepper 0 $ eChange
(eIndex, bCount) <- mapAccum 0 ((\x -> (x, succ x)) <$ eAdd)
let bView = (\n i -> if_ (n==0) (0) i) <$> bCount <*> bCur
bNext = pred <$> bCount
eCreate = (\n -> create tab n bView eChange $ anyEvent [eRef,eAdd]) <$> eIndex
reCreate <- execute eCreate
bItemer <- accumB id $ flip (.) . (:) <$> reCreate
let bItems = ($[]) <$> bItemer
bThis = (widget!?(nullLayouts!!0)) <$> bCur <*> bItems
sink tab [ layout :== bThis ]
liftIO $ set f [ layout := column 5 [ margin 10 $ row 5 [ widget add
, widget prv
, widget cur
, widget nxt
, widget ref
]
, fill $ widget tab
]
]
network <- compile networkDescription
actuate network
>

Couldn't match expected type ‘IO ()’ with actual type ‘(Controller -> IO ()) -> IO ()’

I'm a newbie in Haskell, I took this error when I try to configure my code. I understand that all of instructions in main() need to be an IO(), and the error happened because one of function I used (in Graphics.Gloss.Interface.IO.Animate) didn't return IO(). I wanna display the result of a genetic algorithm by using gloss package.
Here is my code:
module Main where
import Prelude as P
import Control.Monad.Random as Rand
import Data.Functor
import Data.IORef
import Graphics.Gloss.Interface.IO.Animate
import Graphics.Solution
import Graphics.Plot
import Args
import Task
import Parsing
import Genetic
import Control.Concurrent.Async
import Control.Concurrent.STM.TChan
import Control.Monad.STM
import Control.Arrow (first)
main :: IO ()
main = do
args <- parseOptions
opts <- loadEvolOptions (evolOptionsFileName args)
gen <- newStdGen
task#(Task _ twrs _ _) <- loadTask (inputFileName args) (fitnessFuncFileName args)
chan <- newTChanIO
asolution <- async $ solve chan gen opts task
dataRef <- newIORef []
finalSolutionRef <- newIORef Nothing
animateIO mode white $ const $ do
mfinsol <- readIORef finalSolutionRef
case mfinsol of
Just solution -> do
samples <- readIORef dataRef
return $ solutionPicture task solution (fitnessPlot samples)
Nothing -> do
msolution <- poll asolution
case msolution of
Nothing -> do
mv <- atomically $ tryReadTChan chan
case mv of
Nothing -> return ()
Just v -> modifyIORef dataRef (++[v])
samples <- readIORef dataRef
return $ fitnessPlot samples
Just esol -> case esol of
Left e -> fail $ show e
Right solution -> do
saveResult (outputFileName args) (filterTowers solution twrs)
writeIORef finalSolutionRef (Just solution)
samples <- readIORef dataRef
return $ solutionPicture task solution (fitnessPlot samples)
where mode = InWindow "test_genetic_al" (1280, 1024) (10, 10)
fitnessPlot ds = translate (-300) (-200) $ scale 600 600 $ plot "generation" "fitness" $ first fromIntegral <$> ds
And this is which I got:
Couldn't match expected type ‘IO ()’
with actual type ‘(Controller -> IO ()) -> IO ()’
In a stmt of a 'do' block:
animateIO mode white
$ const
$ do { mfinsol <- readIORef finalSolutionRef;
case mfinsol of {
Just solution -> do { ... }
Nothing -> do { ... } } }
In the expression:
do { args <- parseOptions;
opts <- loadEvolOptions (evolOptionsFileName args);
gen <- newStdGen;
task#(Task _ twrs _ _) <- loadTask
(inputFileName args) (fitnessFuncFileName args);
.... }
In an equation for ‘main’:
main
= do { args <- parseOptions;
opts <- loadEvolOptions (evolOptionsFileName args);
gen <- newStdGen;
.... }
where
mode = InWindow "test_genetic_al" (1280, 1024) (10, 10)
fitnessPlot ds
= translate (- 300) (- 200)
$ scale 600 600
$ plot "generation" "fitness" $ first fromIntegral <$> ds
I've been searching my problem over Google and stackoverflow for so many times but still cannot find a solution for this error. Please help me.
P/S: This is a guide line for Graphics.Gloss: https://hackage.haskell.org/package/gloss-1.11.1.1/docs/Graphics-Gloss-Interface-IO-Animate.html
Sorry again for my silly question, after I gave Lazersmoke's suggestion (which you can see below in the comment area), I got another error which very similar with the error I asking for:
I changed the line: animateIO mode white $ const $ do
Into: animateIO mode white (_ -> return ()) $ const $ do
Couldn't match type ‘Picture’ with ‘()’
Expected type: Controller -> IO ()
Actual type: Controller -> IO Picture
In the second argument of ‘($)’, namely
‘const
$ do { mfinsol <- readIORef finalSolutionRef;
case mfinsol of {
Just solution -> do { ... }
Nothing -> do { ... } } }’
In a stmt of a 'do' block:
animateIO mode white (\ _ -> return ())
$ const
$ do { mfinsol <- readIORef finalSolutionRef;
case mfinsol of {
Just solution -> do { ... }
Nothing -> do { ... } } }
In the expression:
do { args <- parseOptions;
opts <- loadEvolOptions (evolOptionsFileName args);
gen <- newStdGen;
task#(Task _ twrs _ _) <- loadTask
(inputFileName args) (fitnessFuncFileName args);
.... }
How many arguments does animateIO take?
animateIO :: Display
-> Color
-> (Float -> IO Picture)
-> (Controller -> IO ())
-> IO ()
Four. How many arguments did you provide to animateIO?
animateIO mode white $ …
Three. The type of
animateIO mode white $ …
is (Controller -> IO ()) -> IO (), which is exactly what your error message tells you. Since you don't want to use the Controller -> IO () part, you can provide your own animateIO:
animateIO' :: Display -> Color -> IO Picture -> IO ()
animateIO' m c a = animateIO m c (const a) (const $ return ())
Note that your (\_ -> return ()) did not work because the third argument has to produce a Picture, not a IO ().

How to convert from happs -> happstack?

Can anyone help me "translate" the below from happs to happstack:
module Main where
import HAppS.Server.AlternativeHTTP
import HAppS.Server.HTTP.AltFileServe
import Control.Monad.State
import Numeric
import Contracts
instance FromData ExContr where
fromData = do c <- look "contract"
arg1 <- look "arg1"
arg2 <- look "arg2"
img <- look "image"
return $ ExContr (c, map fst $ readFloat arg1
++ readFloat arg2, read img)
main :: IO ()
main = do simpleHTTP [dir "contractEx"
[withData $ \(ExContr t) ->
[anyRequest $ liftIO $ liftM toResponse =<< renderEx (ExContr t)]
,anyRequest $ ok $ toResponse renderExDefault]
,fileServe ["Contracts.html"] "public" -- fileserving
]
Contracts.hs contains:
newtype ExContr = ExContr (String, [Double], Bool) deriving (Read,Show,Eq)
renderEx :: ExContr -> IO Html
renderEx exSpec#(ExContr (contractId, args, lattice)) =
let pr = evalEx exSpec
expValChart = if contractId == "probs" then noHtml -- expected value is meaningless for the probabilities it relies on
else h3 << "Expected value" +++ image ! [src (chartUrl $ expectedValuePr pr)]
imageType = "png"
in if useLatticeImage exSpec
then do baseName <- mkUniqueName baseDotFilename
exitCode <- latticeImage pr (webPath ++ tmpImgPath ++ baseName) imageType
let pageContents =
case exitCode of
ExitSuccess -> renderExampleForm exSpec (image ! [src latticeUrl, border 1]) expValChart
where latticeUrl = "/" ++ tmpImgPath ++ baseName ++ "." ++ imageType
_ -> p << "renderEx: error generating lattice image"
return $ renderExamplePage pageContents
else return $ renderExamplePage $ renderExampleForm exSpec (prToTable pr) expValChart
renderExDefault = renderExamplePage $
renderExampleForm (ExContr ("zcb", [fromIntegral t1Horizon, 10], True))
noHtml noHtml
Alternatively I would like to understand how to install an old version of HappS compatible with the above code. Needless to say I am very new to Haskell.
This should work, assuming your ExContr type and renderEx functions that you did not supply in your code are similar to what I have here. I cannot actually run your code to ensure that it behaves the same.
module Main where
import Control.Monad
import Control.Monad.Trans (liftIO)
import Happstack.Server.Internal.Monads (anyRequest)
import Happstack.Server.SimpleHTTP
import Happstack.Server.FileServe
import Numeric
-- data ExContr = ExContr (String, [Double], String)
-- renderEx :: ExContr -> IO String
-- renderEx = undefined
instance FromData ExContr where
fromData = do c <- look "contract"
arg1 <- look "arg1"
arg2 <- look "arg2"
img <- look "image"
return $ ExContr (c, map fst $ readFloat arg1
++ readFloat arg2, read img)
main :: IO ()
main = do
simpleHTTP (nullConf { port = 80 }) $ msum [
dir "contractEx" $ withData $ \(ExContr t) -> msum $ [
anyRequest $ fmap toResponse $ liftIO $ renderEx (ExContr t)
, anyRequest $ ok $ toResponse renderExDefault
]
, serveDirectory DisableBrowsing ["Contracts.html"] "public"
]
Edited: forgot the renderExDefault line.

Resources