Must the operator for a semigroup be defined for all arguments?
Is the example below a correct definition of a semigroup?
instance Semigroup (CurrencyAmount Fixed2) where
(<>) (CurrencyAmount a c) (CurrencyAmount _ EMPTY) = CurrencyAmount a c
(<>) (CurrencyAmount _ EMPTY) (CurrencyAmount a c) = CurrencyAmount a c
(<>) (CurrencyAmount a c1) (CurrencyAmount b c2) | c1 == c2 = CurrencyAmount (a + b) c1
(<>) _ _ = error "currency mismatch"
haskell
add a comment |
Is the example below a correct definition of a semigroup?
instance Semigroup (CurrencyAmount Fixed2) where
(<>) (CurrencyAmount a c) (CurrencyAmount _ EMPTY) = CurrencyAmount a c
(<>) (CurrencyAmount _ EMPTY) (CurrencyAmount a c) = CurrencyAmount a c
(<>) (CurrencyAmount a c1) (CurrencyAmount b c2) | c1 == c2 = CurrencyAmount (a + b) c1
(<>) _ _ = error "currency mismatch"
haskell
The operator should be associative, so you can aim to proof that, and then it is a semigroup.
– Willem Van Onsem
Nov 25 '18 at 9:58
the operator is associative int this example for valid inputs but the <> operator (or function) is not total in this case and I do not know if this is relevant for the prove or not.
– rogergl
Nov 25 '18 at 10:11
The definition ofCurrencyAmount
would be helpful.
– chepner
Nov 26 '18 at 13:56
add a comment |
Is the example below a correct definition of a semigroup?
instance Semigroup (CurrencyAmount Fixed2) where
(<>) (CurrencyAmount a c) (CurrencyAmount _ EMPTY) = CurrencyAmount a c
(<>) (CurrencyAmount _ EMPTY) (CurrencyAmount a c) = CurrencyAmount a c
(<>) (CurrencyAmount a c1) (CurrencyAmount b c2) | c1 == c2 = CurrencyAmount (a + b) c1
(<>) _ _ = error "currency mismatch"
haskell
Is the example below a correct definition of a semigroup?
instance Semigroup (CurrencyAmount Fixed2) where
(<>) (CurrencyAmount a c) (CurrencyAmount _ EMPTY) = CurrencyAmount a c
(<>) (CurrencyAmount _ EMPTY) (CurrencyAmount a c) = CurrencyAmount a c
(<>) (CurrencyAmount a c1) (CurrencyAmount b c2) | c1 == c2 = CurrencyAmount (a + b) c1
(<>) _ _ = error "currency mismatch"
haskell
haskell
edited Nov 25 '18 at 10:54
Mark Seemann
183k33325559
183k33325559
asked Nov 25 '18 at 9:51
rogerglrogergl
1,38211737
1,38211737
The operator should be associative, so you can aim to proof that, and then it is a semigroup.
– Willem Van Onsem
Nov 25 '18 at 9:58
the operator is associative int this example for valid inputs but the <> operator (or function) is not total in this case and I do not know if this is relevant for the prove or not.
– rogergl
Nov 25 '18 at 10:11
The definition ofCurrencyAmount
would be helpful.
– chepner
Nov 26 '18 at 13:56
add a comment |
The operator should be associative, so you can aim to proof that, and then it is a semigroup.
– Willem Van Onsem
Nov 25 '18 at 9:58
the operator is associative int this example for valid inputs but the <> operator (or function) is not total in this case and I do not know if this is relevant for the prove or not.
– rogergl
Nov 25 '18 at 10:11
The definition ofCurrencyAmount
would be helpful.
– chepner
Nov 26 '18 at 13:56
The operator should be associative, so you can aim to proof that, and then it is a semigroup.
– Willem Van Onsem
Nov 25 '18 at 9:58
The operator should be associative, so you can aim to proof that, and then it is a semigroup.
– Willem Van Onsem
Nov 25 '18 at 9:58
the operator is associative int this example for valid inputs but the <> operator (or function) is not total in this case and I do not know if this is relevant for the prove or not.
– rogergl
Nov 25 '18 at 10:11
the operator is associative int this example for valid inputs but the <> operator (or function) is not total in this case and I do not know if this is relevant for the prove or not.
– rogergl
Nov 25 '18 at 10:11
The definition of
CurrencyAmount
would be helpful.– chepner
Nov 26 '18 at 13:56
The definition of
CurrencyAmount
would be helpful.– chepner
Nov 26 '18 at 13:56
add a comment |
2 Answers
2
active
oldest
votes
I suppose this is a matter of semantics. The formal and classical mathematical definition of a Semigroup (A,<>)
does requires <>
to be a function <>:A×A→A
, therefore total. But what is your set A
? You need to establish some (naive) set theoretical based semantics for the (Haskell) types and functions you're working with.
If the denotation of your types are carrier sets that include
⊥
as an element, then your Haskell functions will be interpreted as total mathematical functions. In this case you just have to make sure the required laws hold for all elements including⊥
. And in your case they do.If instead you consider a model of sets (without
⊥
) and partial functions, then to match the classic formal mathematical definition ofSemigroup
you'd need to make sure<>
is total in that setting. And in your case it isn't.
I don't know whether there is a fixed convention. The second, stricter interpretation seems preferable. But the first is a sensible generalisation.
That said have you considered the possibility of using GADTs to distinguish between different currencies at the type level?
Well one can add a dollar to a pound, and have a dollar and a pound. (Like a vector space of currencies).
– n.m.
Nov 25 '18 at 13:33
I don't think including bottom is a useful approach in practice, as it's hard to manipulate diverging computations. Can you write a unit test that verifiesbottom <> bottom == bottom
?
– n.m.
Nov 25 '18 at 15:08
You could say the same for any property involving⊥
though, including strictness. Furthermore, it's not that simple to avoid⊥
. Consider<>
defined on function types. The resulting laws establish equalities on (partial) functions. The Semigroup module itself provides the instanceSemigroup b => Semigroup (a -> b)
wheref <> g = x -> f x <> g x
.
– Jorge Adriano
Nov 25 '18 at 15:39
I can, and I usually do ;) One can reason about the bottom, but one cannot work with it. It is not a useful value --- a program that tries to evaluate it is broken. A program can pass unevaluated bottoms around, but since it cannot look at them, one could replace these bottoms by any other value without affecting the meaning of the program.
– n.m.
Nov 25 '18 at 15:59
I think I like the vector of currencies approach best.
– rogergl
Nov 26 '18 at 8:07
add a comment |
I don't think it's valid.
Most of the lawful type classes in Haskell (e.g. Semigroup
, Monoid
, Functor
, Monad
, etc.) derive their laws from mathematics (e.g. category theory).
Mathematics is based on axioms; that is, assertions about the underlying fabric of numbers, geometry, and similar. By definition, axioms can't be proven, but you usually accept them because they make intuitive sense (e.g. the Peano axioms). In a sense, mathematics is built on a foundation of intuition.
The reason that type classes like the above are lawful is that the laws ensure that the instances behave like you'd expect them to behave.
In Haskell, there's great emphasis on being able to reason about the code, mostly by just looking at the type signatures of functions. One reason you, as a reader, can feel confident about doing this is that whenever a lawful type class is involved, you know that it'll behave in a non-surprising manner.
Most mathematical functions are total (there are exceptions, e.g. division by zero, but exceptions should be drawn from mathematics itself). In light of the above, I'd argue that there's a strong implicit expectation that a type class that derives its laws from mathematics is expected to be total.
The above instance isn't total, which means that it'll behave in a surprising manner for certain inputs. I wouldn't consider it a valid Semigroup
instance.
Yeah. Division.
– n.m.
Nov 25 '18 at 10:56
@n.m. What about division?
– Mark Seemann
Nov 25 '18 at 10:57
1
Is it total? What's its domain? To what Haskell type does said domain correspond?
– n.m.
Nov 25 '18 at 10:59
@n.m. It's not uncommon in mathematics that functions can be "undefined" at points not in its domain. Do we consider the zero denominator part of the division function's domain?
– Mark Seemann
Nov 25 '18 at 11:07
@n.m. Not that I don't get your point. In Haskell, division is clearly not total, so it does invalidate my argument. Do you, however, find the OP instance valid?
– Mark Seemann
Nov 25 '18 at 11:08
|
show 5 more comments
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%2f53466359%2fmust-the-operator-for-a-semigroup-be-defined-for-all-arguments%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
I suppose this is a matter of semantics. The formal and classical mathematical definition of a Semigroup (A,<>)
does requires <>
to be a function <>:A×A→A
, therefore total. But what is your set A
? You need to establish some (naive) set theoretical based semantics for the (Haskell) types and functions you're working with.
If the denotation of your types are carrier sets that include
⊥
as an element, then your Haskell functions will be interpreted as total mathematical functions. In this case you just have to make sure the required laws hold for all elements including⊥
. And in your case they do.If instead you consider a model of sets (without
⊥
) and partial functions, then to match the classic formal mathematical definition ofSemigroup
you'd need to make sure<>
is total in that setting. And in your case it isn't.
I don't know whether there is a fixed convention. The second, stricter interpretation seems preferable. But the first is a sensible generalisation.
That said have you considered the possibility of using GADTs to distinguish between different currencies at the type level?
Well one can add a dollar to a pound, and have a dollar and a pound. (Like a vector space of currencies).
– n.m.
Nov 25 '18 at 13:33
I don't think including bottom is a useful approach in practice, as it's hard to manipulate diverging computations. Can you write a unit test that verifiesbottom <> bottom == bottom
?
– n.m.
Nov 25 '18 at 15:08
You could say the same for any property involving⊥
though, including strictness. Furthermore, it's not that simple to avoid⊥
. Consider<>
defined on function types. The resulting laws establish equalities on (partial) functions. The Semigroup module itself provides the instanceSemigroup b => Semigroup (a -> b)
wheref <> g = x -> f x <> g x
.
– Jorge Adriano
Nov 25 '18 at 15:39
I can, and I usually do ;) One can reason about the bottom, but one cannot work with it. It is not a useful value --- a program that tries to evaluate it is broken. A program can pass unevaluated bottoms around, but since it cannot look at them, one could replace these bottoms by any other value without affecting the meaning of the program.
– n.m.
Nov 25 '18 at 15:59
I think I like the vector of currencies approach best.
– rogergl
Nov 26 '18 at 8:07
add a comment |
I suppose this is a matter of semantics. The formal and classical mathematical definition of a Semigroup (A,<>)
does requires <>
to be a function <>:A×A→A
, therefore total. But what is your set A
? You need to establish some (naive) set theoretical based semantics for the (Haskell) types and functions you're working with.
If the denotation of your types are carrier sets that include
⊥
as an element, then your Haskell functions will be interpreted as total mathematical functions. In this case you just have to make sure the required laws hold for all elements including⊥
. And in your case they do.If instead you consider a model of sets (without
⊥
) and partial functions, then to match the classic formal mathematical definition ofSemigroup
you'd need to make sure<>
is total in that setting. And in your case it isn't.
I don't know whether there is a fixed convention. The second, stricter interpretation seems preferable. But the first is a sensible generalisation.
That said have you considered the possibility of using GADTs to distinguish between different currencies at the type level?
Well one can add a dollar to a pound, and have a dollar and a pound. (Like a vector space of currencies).
– n.m.
Nov 25 '18 at 13:33
I don't think including bottom is a useful approach in practice, as it's hard to manipulate diverging computations. Can you write a unit test that verifiesbottom <> bottom == bottom
?
– n.m.
Nov 25 '18 at 15:08
You could say the same for any property involving⊥
though, including strictness. Furthermore, it's not that simple to avoid⊥
. Consider<>
defined on function types. The resulting laws establish equalities on (partial) functions. The Semigroup module itself provides the instanceSemigroup b => Semigroup (a -> b)
wheref <> g = x -> f x <> g x
.
– Jorge Adriano
Nov 25 '18 at 15:39
I can, and I usually do ;) One can reason about the bottom, but one cannot work with it. It is not a useful value --- a program that tries to evaluate it is broken. A program can pass unevaluated bottoms around, but since it cannot look at them, one could replace these bottoms by any other value without affecting the meaning of the program.
– n.m.
Nov 25 '18 at 15:59
I think I like the vector of currencies approach best.
– rogergl
Nov 26 '18 at 8:07
add a comment |
I suppose this is a matter of semantics. The formal and classical mathematical definition of a Semigroup (A,<>)
does requires <>
to be a function <>:A×A→A
, therefore total. But what is your set A
? You need to establish some (naive) set theoretical based semantics for the (Haskell) types and functions you're working with.
If the denotation of your types are carrier sets that include
⊥
as an element, then your Haskell functions will be interpreted as total mathematical functions. In this case you just have to make sure the required laws hold for all elements including⊥
. And in your case they do.If instead you consider a model of sets (without
⊥
) and partial functions, then to match the classic formal mathematical definition ofSemigroup
you'd need to make sure<>
is total in that setting. And in your case it isn't.
I don't know whether there is a fixed convention. The second, stricter interpretation seems preferable. But the first is a sensible generalisation.
That said have you considered the possibility of using GADTs to distinguish between different currencies at the type level?
I suppose this is a matter of semantics. The formal and classical mathematical definition of a Semigroup (A,<>)
does requires <>
to be a function <>:A×A→A
, therefore total. But what is your set A
? You need to establish some (naive) set theoretical based semantics for the (Haskell) types and functions you're working with.
If the denotation of your types are carrier sets that include
⊥
as an element, then your Haskell functions will be interpreted as total mathematical functions. In this case you just have to make sure the required laws hold for all elements including⊥
. And in your case they do.If instead you consider a model of sets (without
⊥
) and partial functions, then to match the classic formal mathematical definition ofSemigroup
you'd need to make sure<>
is total in that setting. And in your case it isn't.
I don't know whether there is a fixed convention. The second, stricter interpretation seems preferable. But the first is a sensible generalisation.
That said have you considered the possibility of using GADTs to distinguish between different currencies at the type level?
edited Nov 25 '18 at 11:29
answered Nov 25 '18 at 11:21
Jorge AdrianoJorge Adriano
2,220918
2,220918
Well one can add a dollar to a pound, and have a dollar and a pound. (Like a vector space of currencies).
– n.m.
Nov 25 '18 at 13:33
I don't think including bottom is a useful approach in practice, as it's hard to manipulate diverging computations. Can you write a unit test that verifiesbottom <> bottom == bottom
?
– n.m.
Nov 25 '18 at 15:08
You could say the same for any property involving⊥
though, including strictness. Furthermore, it's not that simple to avoid⊥
. Consider<>
defined on function types. The resulting laws establish equalities on (partial) functions. The Semigroup module itself provides the instanceSemigroup b => Semigroup (a -> b)
wheref <> g = x -> f x <> g x
.
– Jorge Adriano
Nov 25 '18 at 15:39
I can, and I usually do ;) One can reason about the bottom, but one cannot work with it. It is not a useful value --- a program that tries to evaluate it is broken. A program can pass unevaluated bottoms around, but since it cannot look at them, one could replace these bottoms by any other value without affecting the meaning of the program.
– n.m.
Nov 25 '18 at 15:59
I think I like the vector of currencies approach best.
– rogergl
Nov 26 '18 at 8:07
add a comment |
Well one can add a dollar to a pound, and have a dollar and a pound. (Like a vector space of currencies).
– n.m.
Nov 25 '18 at 13:33
I don't think including bottom is a useful approach in practice, as it's hard to manipulate diverging computations. Can you write a unit test that verifiesbottom <> bottom == bottom
?
– n.m.
Nov 25 '18 at 15:08
You could say the same for any property involving⊥
though, including strictness. Furthermore, it's not that simple to avoid⊥
. Consider<>
defined on function types. The resulting laws establish equalities on (partial) functions. The Semigroup module itself provides the instanceSemigroup b => Semigroup (a -> b)
wheref <> g = x -> f x <> g x
.
– Jorge Adriano
Nov 25 '18 at 15:39
I can, and I usually do ;) One can reason about the bottom, but one cannot work with it. It is not a useful value --- a program that tries to evaluate it is broken. A program can pass unevaluated bottoms around, but since it cannot look at them, one could replace these bottoms by any other value without affecting the meaning of the program.
– n.m.
Nov 25 '18 at 15:59
I think I like the vector of currencies approach best.
– rogergl
Nov 26 '18 at 8:07
Well one can add a dollar to a pound, and have a dollar and a pound. (Like a vector space of currencies).
– n.m.
Nov 25 '18 at 13:33
Well one can add a dollar to a pound, and have a dollar and a pound. (Like a vector space of currencies).
– n.m.
Nov 25 '18 at 13:33
I don't think including bottom is a useful approach in practice, as it's hard to manipulate diverging computations. Can you write a unit test that verifies
bottom <> bottom == bottom
?– n.m.
Nov 25 '18 at 15:08
I don't think including bottom is a useful approach in practice, as it's hard to manipulate diverging computations. Can you write a unit test that verifies
bottom <> bottom == bottom
?– n.m.
Nov 25 '18 at 15:08
You could say the same for any property involving
⊥
though, including strictness. Furthermore, it's not that simple to avoid ⊥
. Consider <>
defined on function types. The resulting laws establish equalities on (partial) functions. The Semigroup module itself provides the instance Semigroup b => Semigroup (a -> b)
where f <> g = x -> f x <> g x
.– Jorge Adriano
Nov 25 '18 at 15:39
You could say the same for any property involving
⊥
though, including strictness. Furthermore, it's not that simple to avoid ⊥
. Consider <>
defined on function types. The resulting laws establish equalities on (partial) functions. The Semigroup module itself provides the instance Semigroup b => Semigroup (a -> b)
where f <> g = x -> f x <> g x
.– Jorge Adriano
Nov 25 '18 at 15:39
I can, and I usually do ;) One can reason about the bottom, but one cannot work with it. It is not a useful value --- a program that tries to evaluate it is broken. A program can pass unevaluated bottoms around, but since it cannot look at them, one could replace these bottoms by any other value without affecting the meaning of the program.
– n.m.
Nov 25 '18 at 15:59
I can, and I usually do ;) One can reason about the bottom, but one cannot work with it. It is not a useful value --- a program that tries to evaluate it is broken. A program can pass unevaluated bottoms around, but since it cannot look at them, one could replace these bottoms by any other value without affecting the meaning of the program.
– n.m.
Nov 25 '18 at 15:59
I think I like the vector of currencies approach best.
– rogergl
Nov 26 '18 at 8:07
I think I like the vector of currencies approach best.
– rogergl
Nov 26 '18 at 8:07
add a comment |
I don't think it's valid.
Most of the lawful type classes in Haskell (e.g. Semigroup
, Monoid
, Functor
, Monad
, etc.) derive their laws from mathematics (e.g. category theory).
Mathematics is based on axioms; that is, assertions about the underlying fabric of numbers, geometry, and similar. By definition, axioms can't be proven, but you usually accept them because they make intuitive sense (e.g. the Peano axioms). In a sense, mathematics is built on a foundation of intuition.
The reason that type classes like the above are lawful is that the laws ensure that the instances behave like you'd expect them to behave.
In Haskell, there's great emphasis on being able to reason about the code, mostly by just looking at the type signatures of functions. One reason you, as a reader, can feel confident about doing this is that whenever a lawful type class is involved, you know that it'll behave in a non-surprising manner.
Most mathematical functions are total (there are exceptions, e.g. division by zero, but exceptions should be drawn from mathematics itself). In light of the above, I'd argue that there's a strong implicit expectation that a type class that derives its laws from mathematics is expected to be total.
The above instance isn't total, which means that it'll behave in a surprising manner for certain inputs. I wouldn't consider it a valid Semigroup
instance.
Yeah. Division.
– n.m.
Nov 25 '18 at 10:56
@n.m. What about division?
– Mark Seemann
Nov 25 '18 at 10:57
1
Is it total? What's its domain? To what Haskell type does said domain correspond?
– n.m.
Nov 25 '18 at 10:59
@n.m. It's not uncommon in mathematics that functions can be "undefined" at points not in its domain. Do we consider the zero denominator part of the division function's domain?
– Mark Seemann
Nov 25 '18 at 11:07
@n.m. Not that I don't get your point. In Haskell, division is clearly not total, so it does invalidate my argument. Do you, however, find the OP instance valid?
– Mark Seemann
Nov 25 '18 at 11:08
|
show 5 more comments
I don't think it's valid.
Most of the lawful type classes in Haskell (e.g. Semigroup
, Monoid
, Functor
, Monad
, etc.) derive their laws from mathematics (e.g. category theory).
Mathematics is based on axioms; that is, assertions about the underlying fabric of numbers, geometry, and similar. By definition, axioms can't be proven, but you usually accept them because they make intuitive sense (e.g. the Peano axioms). In a sense, mathematics is built on a foundation of intuition.
The reason that type classes like the above are lawful is that the laws ensure that the instances behave like you'd expect them to behave.
In Haskell, there's great emphasis on being able to reason about the code, mostly by just looking at the type signatures of functions. One reason you, as a reader, can feel confident about doing this is that whenever a lawful type class is involved, you know that it'll behave in a non-surprising manner.
Most mathematical functions are total (there are exceptions, e.g. division by zero, but exceptions should be drawn from mathematics itself). In light of the above, I'd argue that there's a strong implicit expectation that a type class that derives its laws from mathematics is expected to be total.
The above instance isn't total, which means that it'll behave in a surprising manner for certain inputs. I wouldn't consider it a valid Semigroup
instance.
Yeah. Division.
– n.m.
Nov 25 '18 at 10:56
@n.m. What about division?
– Mark Seemann
Nov 25 '18 at 10:57
1
Is it total? What's its domain? To what Haskell type does said domain correspond?
– n.m.
Nov 25 '18 at 10:59
@n.m. It's not uncommon in mathematics that functions can be "undefined" at points not in its domain. Do we consider the zero denominator part of the division function's domain?
– Mark Seemann
Nov 25 '18 at 11:07
@n.m. Not that I don't get your point. In Haskell, division is clearly not total, so it does invalidate my argument. Do you, however, find the OP instance valid?
– Mark Seemann
Nov 25 '18 at 11:08
|
show 5 more comments
I don't think it's valid.
Most of the lawful type classes in Haskell (e.g. Semigroup
, Monoid
, Functor
, Monad
, etc.) derive their laws from mathematics (e.g. category theory).
Mathematics is based on axioms; that is, assertions about the underlying fabric of numbers, geometry, and similar. By definition, axioms can't be proven, but you usually accept them because they make intuitive sense (e.g. the Peano axioms). In a sense, mathematics is built on a foundation of intuition.
The reason that type classes like the above are lawful is that the laws ensure that the instances behave like you'd expect them to behave.
In Haskell, there's great emphasis on being able to reason about the code, mostly by just looking at the type signatures of functions. One reason you, as a reader, can feel confident about doing this is that whenever a lawful type class is involved, you know that it'll behave in a non-surprising manner.
Most mathematical functions are total (there are exceptions, e.g. division by zero, but exceptions should be drawn from mathematics itself). In light of the above, I'd argue that there's a strong implicit expectation that a type class that derives its laws from mathematics is expected to be total.
The above instance isn't total, which means that it'll behave in a surprising manner for certain inputs. I wouldn't consider it a valid Semigroup
instance.
I don't think it's valid.
Most of the lawful type classes in Haskell (e.g. Semigroup
, Monoid
, Functor
, Monad
, etc.) derive their laws from mathematics (e.g. category theory).
Mathematics is based on axioms; that is, assertions about the underlying fabric of numbers, geometry, and similar. By definition, axioms can't be proven, but you usually accept them because they make intuitive sense (e.g. the Peano axioms). In a sense, mathematics is built on a foundation of intuition.
The reason that type classes like the above are lawful is that the laws ensure that the instances behave like you'd expect them to behave.
In Haskell, there's great emphasis on being able to reason about the code, mostly by just looking at the type signatures of functions. One reason you, as a reader, can feel confident about doing this is that whenever a lawful type class is involved, you know that it'll behave in a non-surprising manner.
Most mathematical functions are total (there are exceptions, e.g. division by zero, but exceptions should be drawn from mathematics itself). In light of the above, I'd argue that there's a strong implicit expectation that a type class that derives its laws from mathematics is expected to be total.
The above instance isn't total, which means that it'll behave in a surprising manner for certain inputs. I wouldn't consider it a valid Semigroup
instance.
edited Nov 25 '18 at 11:26
answered Nov 25 '18 at 10:53
Mark SeemannMark Seemann
183k33325559
183k33325559
Yeah. Division.
– n.m.
Nov 25 '18 at 10:56
@n.m. What about division?
– Mark Seemann
Nov 25 '18 at 10:57
1
Is it total? What's its domain? To what Haskell type does said domain correspond?
– n.m.
Nov 25 '18 at 10:59
@n.m. It's not uncommon in mathematics that functions can be "undefined" at points not in its domain. Do we consider the zero denominator part of the division function's domain?
– Mark Seemann
Nov 25 '18 at 11:07
@n.m. Not that I don't get your point. In Haskell, division is clearly not total, so it does invalidate my argument. Do you, however, find the OP instance valid?
– Mark Seemann
Nov 25 '18 at 11:08
|
show 5 more comments
Yeah. Division.
– n.m.
Nov 25 '18 at 10:56
@n.m. What about division?
– Mark Seemann
Nov 25 '18 at 10:57
1
Is it total? What's its domain? To what Haskell type does said domain correspond?
– n.m.
Nov 25 '18 at 10:59
@n.m. It's not uncommon in mathematics that functions can be "undefined" at points not in its domain. Do we consider the zero denominator part of the division function's domain?
– Mark Seemann
Nov 25 '18 at 11:07
@n.m. Not that I don't get your point. In Haskell, division is clearly not total, so it does invalidate my argument. Do you, however, find the OP instance valid?
– Mark Seemann
Nov 25 '18 at 11:08
Yeah. Division.
– n.m.
Nov 25 '18 at 10:56
Yeah. Division.
– n.m.
Nov 25 '18 at 10:56
@n.m. What about division?
– Mark Seemann
Nov 25 '18 at 10:57
@n.m. What about division?
– Mark Seemann
Nov 25 '18 at 10:57
1
1
Is it total? What's its domain? To what Haskell type does said domain correspond?
– n.m.
Nov 25 '18 at 10:59
Is it total? What's its domain? To what Haskell type does said domain correspond?
– n.m.
Nov 25 '18 at 10:59
@n.m. It's not uncommon in mathematics that functions can be "undefined" at points not in its domain. Do we consider the zero denominator part of the division function's domain?
– Mark Seemann
Nov 25 '18 at 11:07
@n.m. It's not uncommon in mathematics that functions can be "undefined" at points not in its domain. Do we consider the zero denominator part of the division function's domain?
– Mark Seemann
Nov 25 '18 at 11:07
@n.m. Not that I don't get your point. In Haskell, division is clearly not total, so it does invalidate my argument. Do you, however, find the OP instance valid?
– Mark Seemann
Nov 25 '18 at 11:08
@n.m. Not that I don't get your point. In Haskell, division is clearly not total, so it does invalidate my argument. Do you, however, find the OP instance valid?
– Mark Seemann
Nov 25 '18 at 11:08
|
show 5 more comments
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.
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%2f53466359%2fmust-the-operator-for-a-semigroup-be-defined-for-all-arguments%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
The operator should be associative, so you can aim to proof that, and then it is a semigroup.
– Willem Van Onsem
Nov 25 '18 at 9:58
the operator is associative int this example for valid inputs but the <> operator (or function) is not total in this case and I do not know if this is relevant for the prove or not.
– rogergl
Nov 25 '18 at 10:11
The definition of
CurrencyAmount
would be helpful.– chepner
Nov 26 '18 at 13:56