What are the best ways to do field-wise datatype operations?
Say I have a datatype like:
data CpuStatRow a = CpuStatRow
{ user :: a
, nice :: a
, system :: a
, idle :: a
, ioWait :: a
, irq :: a
, softIrq :: a
, steal :: a
}
which comes from parsing CPU info from /proc/stat of a linux OS, in which every numeric field is an accumulative value since boot time. So if I want to figure out values during certain period, I need to grab before :: CpuStatRow Int
and after :: CpuStatRow Int
and do the field-wise difference (assuming proper language extensions):
-- let's not worry about distinction between a raw value and a difference for now ...
type Diff = Int
getDiff :: CpuStatRow Int -> CpuStatRow Int -> CpuStatRow Diff
getDiff after before = CpuStatRow {..}
where
diffOn prj = prj after - prj before
user = diffOn user
nice = diffOn nice
... -- basically same for each field
I'm wondering is there something better to do that:
- generalize to function of other aritieis (e.g. lift a function
f :: a -> b -> c -> d
to somef' :: F a -> F b -> F c -> F d
- can easily work on any datatype, as there are many accumulative values in
/proc
, applying the same method above is not fun. I haveApplicative
in mind but that doesn't seems to be "deriving-able" by ghc
haskell
add a comment |
Say I have a datatype like:
data CpuStatRow a = CpuStatRow
{ user :: a
, nice :: a
, system :: a
, idle :: a
, ioWait :: a
, irq :: a
, softIrq :: a
, steal :: a
}
which comes from parsing CPU info from /proc/stat of a linux OS, in which every numeric field is an accumulative value since boot time. So if I want to figure out values during certain period, I need to grab before :: CpuStatRow Int
and after :: CpuStatRow Int
and do the field-wise difference (assuming proper language extensions):
-- let's not worry about distinction between a raw value and a difference for now ...
type Diff = Int
getDiff :: CpuStatRow Int -> CpuStatRow Int -> CpuStatRow Diff
getDiff after before = CpuStatRow {..}
where
diffOn prj = prj after - prj before
user = diffOn user
nice = diffOn nice
... -- basically same for each field
I'm wondering is there something better to do that:
- generalize to function of other aritieis (e.g. lift a function
f :: a -> b -> c -> d
to somef' :: F a -> F b -> F c -> F d
- can easily work on any datatype, as there are many accumulative values in
/proc
, applying the same method above is not fun. I haveApplicative
in mind but that doesn't seems to be "deriving-able" by ghc
haskell
wouldn't it make sense modelling the CpuStateRow using Map?
– ƛƛƛ
Nov 20 at 18:35
@ƛƛƛ but that'll impose an extra lookup overhead that I don't necessarily need - I already know all fields and there's no adding / removing of them.
– Javran
Nov 20 at 19:15
add a comment |
Say I have a datatype like:
data CpuStatRow a = CpuStatRow
{ user :: a
, nice :: a
, system :: a
, idle :: a
, ioWait :: a
, irq :: a
, softIrq :: a
, steal :: a
}
which comes from parsing CPU info from /proc/stat of a linux OS, in which every numeric field is an accumulative value since boot time. So if I want to figure out values during certain period, I need to grab before :: CpuStatRow Int
and after :: CpuStatRow Int
and do the field-wise difference (assuming proper language extensions):
-- let's not worry about distinction between a raw value and a difference for now ...
type Diff = Int
getDiff :: CpuStatRow Int -> CpuStatRow Int -> CpuStatRow Diff
getDiff after before = CpuStatRow {..}
where
diffOn prj = prj after - prj before
user = diffOn user
nice = diffOn nice
... -- basically same for each field
I'm wondering is there something better to do that:
- generalize to function of other aritieis (e.g. lift a function
f :: a -> b -> c -> d
to somef' :: F a -> F b -> F c -> F d
- can easily work on any datatype, as there are many accumulative values in
/proc
, applying the same method above is not fun. I haveApplicative
in mind but that doesn't seems to be "deriving-able" by ghc
haskell
Say I have a datatype like:
data CpuStatRow a = CpuStatRow
{ user :: a
, nice :: a
, system :: a
, idle :: a
, ioWait :: a
, irq :: a
, softIrq :: a
, steal :: a
}
which comes from parsing CPU info from /proc/stat of a linux OS, in which every numeric field is an accumulative value since boot time. So if I want to figure out values during certain period, I need to grab before :: CpuStatRow Int
and after :: CpuStatRow Int
and do the field-wise difference (assuming proper language extensions):
-- let's not worry about distinction between a raw value and a difference for now ...
type Diff = Int
getDiff :: CpuStatRow Int -> CpuStatRow Int -> CpuStatRow Diff
getDiff after before = CpuStatRow {..}
where
diffOn prj = prj after - prj before
user = diffOn user
nice = diffOn nice
... -- basically same for each field
I'm wondering is there something better to do that:
- generalize to function of other aritieis (e.g. lift a function
f :: a -> b -> c -> d
to somef' :: F a -> F b -> F c -> F d
- can easily work on any datatype, as there are many accumulative values in
/proc
, applying the same method above is not fun. I haveApplicative
in mind but that doesn't seems to be "deriving-able" by ghc
haskell
haskell
asked Nov 20 at 18:11
Javran
1,48911433
1,48911433
wouldn't it make sense modelling the CpuStateRow using Map?
– ƛƛƛ
Nov 20 at 18:35
@ƛƛƛ but that'll impose an extra lookup overhead that I don't necessarily need - I already know all fields and there's no adding / removing of them.
– Javran
Nov 20 at 19:15
add a comment |
wouldn't it make sense modelling the CpuStateRow using Map?
– ƛƛƛ
Nov 20 at 18:35
@ƛƛƛ but that'll impose an extra lookup overhead that I don't necessarily need - I already know all fields and there's no adding / removing of them.
– Javran
Nov 20 at 19:15
wouldn't it make sense modelling the CpuStateRow using Map?
– ƛƛƛ
Nov 20 at 18:35
wouldn't it make sense modelling the CpuStateRow using Map?
– ƛƛƛ
Nov 20 at 18:35
@ƛƛƛ but that'll impose an extra lookup overhead that I don't necessarily need - I already know all fields and there's no adding / removing of them.
– Javran
Nov 20 at 19:15
@ƛƛƛ but that'll impose an extra lookup overhead that I don't necessarily need - I already know all fields and there's no adding / removing of them.
– Javran
Nov 20 at 19:15
add a comment |
1 Answer
1
active
oldest
votes
If you want to generalize to functions of any arity and any argument type, I think Applicative is the best you will find. Indeed you won't be able to derive it, but at least you can implement pure
and (<*>)
once and then reuse it for all of your functions rather than having to do the tedium for each of them. And you can ask GHC to derive the Functor instance for you, if nothing else.
If you want to work with "accumulative values" instead of general functions, you could consider adding a Monoid (or just Semigroup) instance, of the form
instance Semigroup a => Semigroup (CpuStatRow a) where
(CpuStatRow x y z ...) <> (CpuStatRow x' y' z') = CpuStatRow (x <> x') (y <> y') (z <> z') ...
As you can imagine that would get tiring quickly, but fortunately you can implement it in terms of Applicative - we're already saving time!
instance Semigroup a => Semigroup (CpuStatRow a) where
(<>) = liftA2 (<>)
instance Monoid a => Monoid (CpuStatRow a) where
mempty = pure mempty
thanks for the answer! perhaps a bit off topic but I'm wondering if I can write Applicative instances with template haskell?
– Javran
Nov 20 at 23:46
I'm sure it is possible for a type as regular as this, but I don't think enough people are writing a ton of types equivalent to(a,a,a,a,a,a,a,a)
that this would be built into any library without having to do some work yourself.
– amalloy
Nov 21 at 5:47
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53399049%2fwhat-are-the-best-ways-to-do-field-wise-datatype-operations%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
If you want to generalize to functions of any arity and any argument type, I think Applicative is the best you will find. Indeed you won't be able to derive it, but at least you can implement pure
and (<*>)
once and then reuse it for all of your functions rather than having to do the tedium for each of them. And you can ask GHC to derive the Functor instance for you, if nothing else.
If you want to work with "accumulative values" instead of general functions, you could consider adding a Monoid (or just Semigroup) instance, of the form
instance Semigroup a => Semigroup (CpuStatRow a) where
(CpuStatRow x y z ...) <> (CpuStatRow x' y' z') = CpuStatRow (x <> x') (y <> y') (z <> z') ...
As you can imagine that would get tiring quickly, but fortunately you can implement it in terms of Applicative - we're already saving time!
instance Semigroup a => Semigroup (CpuStatRow a) where
(<>) = liftA2 (<>)
instance Monoid a => Monoid (CpuStatRow a) where
mempty = pure mempty
thanks for the answer! perhaps a bit off topic but I'm wondering if I can write Applicative instances with template haskell?
– Javran
Nov 20 at 23:46
I'm sure it is possible for a type as regular as this, but I don't think enough people are writing a ton of types equivalent to(a,a,a,a,a,a,a,a)
that this would be built into any library without having to do some work yourself.
– amalloy
Nov 21 at 5:47
add a comment |
If you want to generalize to functions of any arity and any argument type, I think Applicative is the best you will find. Indeed you won't be able to derive it, but at least you can implement pure
and (<*>)
once and then reuse it for all of your functions rather than having to do the tedium for each of them. And you can ask GHC to derive the Functor instance for you, if nothing else.
If you want to work with "accumulative values" instead of general functions, you could consider adding a Monoid (or just Semigroup) instance, of the form
instance Semigroup a => Semigroup (CpuStatRow a) where
(CpuStatRow x y z ...) <> (CpuStatRow x' y' z') = CpuStatRow (x <> x') (y <> y') (z <> z') ...
As you can imagine that would get tiring quickly, but fortunately you can implement it in terms of Applicative - we're already saving time!
instance Semigroup a => Semigroup (CpuStatRow a) where
(<>) = liftA2 (<>)
instance Monoid a => Monoid (CpuStatRow a) where
mempty = pure mempty
thanks for the answer! perhaps a bit off topic but I'm wondering if I can write Applicative instances with template haskell?
– Javran
Nov 20 at 23:46
I'm sure it is possible for a type as regular as this, but I don't think enough people are writing a ton of types equivalent to(a,a,a,a,a,a,a,a)
that this would be built into any library without having to do some work yourself.
– amalloy
Nov 21 at 5:47
add a comment |
If you want to generalize to functions of any arity and any argument type, I think Applicative is the best you will find. Indeed you won't be able to derive it, but at least you can implement pure
and (<*>)
once and then reuse it for all of your functions rather than having to do the tedium for each of them. And you can ask GHC to derive the Functor instance for you, if nothing else.
If you want to work with "accumulative values" instead of general functions, you could consider adding a Monoid (or just Semigroup) instance, of the form
instance Semigroup a => Semigroup (CpuStatRow a) where
(CpuStatRow x y z ...) <> (CpuStatRow x' y' z') = CpuStatRow (x <> x') (y <> y') (z <> z') ...
As you can imagine that would get tiring quickly, but fortunately you can implement it in terms of Applicative - we're already saving time!
instance Semigroup a => Semigroup (CpuStatRow a) where
(<>) = liftA2 (<>)
instance Monoid a => Monoid (CpuStatRow a) where
mempty = pure mempty
If you want to generalize to functions of any arity and any argument type, I think Applicative is the best you will find. Indeed you won't be able to derive it, but at least you can implement pure
and (<*>)
once and then reuse it for all of your functions rather than having to do the tedium for each of them. And you can ask GHC to derive the Functor instance for you, if nothing else.
If you want to work with "accumulative values" instead of general functions, you could consider adding a Monoid (or just Semigroup) instance, of the form
instance Semigroup a => Semigroup (CpuStatRow a) where
(CpuStatRow x y z ...) <> (CpuStatRow x' y' z') = CpuStatRow (x <> x') (y <> y') (z <> z') ...
As you can imagine that would get tiring quickly, but fortunately you can implement it in terms of Applicative - we're already saving time!
instance Semigroup a => Semigroup (CpuStatRow a) where
(<>) = liftA2 (<>)
instance Monoid a => Monoid (CpuStatRow a) where
mempty = pure mempty
answered Nov 20 at 18:28
amalloy
58.7k5101153
58.7k5101153
thanks for the answer! perhaps a bit off topic but I'm wondering if I can write Applicative instances with template haskell?
– Javran
Nov 20 at 23:46
I'm sure it is possible for a type as regular as this, but I don't think enough people are writing a ton of types equivalent to(a,a,a,a,a,a,a,a)
that this would be built into any library without having to do some work yourself.
– amalloy
Nov 21 at 5:47
add a comment |
thanks for the answer! perhaps a bit off topic but I'm wondering if I can write Applicative instances with template haskell?
– Javran
Nov 20 at 23:46
I'm sure it is possible for a type as regular as this, but I don't think enough people are writing a ton of types equivalent to(a,a,a,a,a,a,a,a)
that this would be built into any library without having to do some work yourself.
– amalloy
Nov 21 at 5:47
thanks for the answer! perhaps a bit off topic but I'm wondering if I can write Applicative instances with template haskell?
– Javran
Nov 20 at 23:46
thanks for the answer! perhaps a bit off topic but I'm wondering if I can write Applicative instances with template haskell?
– Javran
Nov 20 at 23:46
I'm sure it is possible for a type as regular as this, but I don't think enough people are writing a ton of types equivalent to
(a,a,a,a,a,a,a,a)
that this would be built into any library without having to do some work yourself.– amalloy
Nov 21 at 5:47
I'm sure it is possible for a type as regular as this, but I don't think enough people are writing a ton of types equivalent to
(a,a,a,a,a,a,a,a)
that this would be built into any library without having to do some work yourself.– amalloy
Nov 21 at 5:47
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53399049%2fwhat-are-the-best-ways-to-do-field-wise-datatype-operations%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
wouldn't it make sense modelling the CpuStateRow using Map?
– ƛƛƛ
Nov 20 at 18:35
@ƛƛƛ but that'll impose an extra lookup overhead that I don't necessarily need - I already know all fields and there's no adding / removing of them.
– Javran
Nov 20 at 19:15