Is there a "unit"? Would it be helpful?

Is there a class for types with a single value (not sure of the correct terminology here), i.e. types with some given value?

class Unit a where unit :: a instance Unit () where unit = () instance Unit (Maybe a) where unit = Nothing 

... for all monoids, MonadPlus, etc.

I suggest that another name for the class might be Default . This would be useful twice recently for me.

Probably flimsy example:

 extract :: (Unit r)=> Reader ra -> a extract r = runReader r unit 

Does it exist? Others find this to be useful?

+6
source share
3 answers

Yes, that would be helpful. In fact, all slightly incompatible versions would be useful! What a problem.

It is unclear what such a class can mean, which makes it difficult to use, because inevitably you will come across types where there are several default options, and if it does not immediately clear the one that the instance provides, you will lose all the advantages of having the class first of all.

A few examples:

  • For Monoid instances Monoid you obviously expect the identity element to be the default. But now you are again faced with the problem of many types having two or more reasonable Monoid instances. Is the default value of Integer 0 or 1? For Monoid , the standard library uses newtype wrappers, but this is inconvenient and makes it difficult to work with wrapped types - it works fine with Monoid because you get access to mconcat and the like, but you can’t do anything interesting by default.

  • For Functor types with an "empty" value, which gives an obvious default value. This is what MonadPlus and Alternative , and also overlap with Monoid , and if the memory serves me at least one type where these three instances are not identical. What do you choose when there is more than one choice? Consider the lists: you can blindly add them by providing an arbitrary Monoid , with an empty list as a person; but for Monoids lists Monoids you can also zipWith mappend by providing a raised monoid with repeat mempty as an identity. Many functors have similar instances of Monoid , but not always both - so what you choose for lists will be conceptually incompatible with some other Functor !

  • For device types such as () , it's not hard to choose a default value! But what about transfers? Does it make sense to choose the first constructor? Sometimes, but not always. How do people familiar with the class know?

  • How about Bounded ? If none of the above applies, you can use minBound . But some of the above types may be Bounded , so you will confuse the questions if their default value is not their minimum value.

In principle, there is enough coincidence, which seems to make sense ... but in fact you have at least three different types of classes, and trying to unify them is probably not as useful as it seems at first glance.


If you can sort things out a bit and give a clear, consistent semantic interpretation of the default value without rethinking Monoid or another existing class to make the type class easy to use, stop and think about choosing a default, great! But I will not hope that this works.

However, it is obvious that a reasonable case, which is not covered by any class of the standard type, are singleton like () . In most cases, this is not very useful - for obvious reasons! - perhaps that's why there is no such class. However, one place where such a class is extremely useful is when you do something that is related to type type tinans, because that type represents the same value both at the type level and at the term level, therefore the class for such types allows you to freely manipulate type level values, and then call the term that comes with it, so you can pass it to some other function that can, for example, select an instance of a type class based on it. For this reason, I have a class on these lines in my ever-incomplete hackery type library , for example:

 class TermProxy t where term :: t -- This makes explicit the lexical pun of () having type (). instance TermProxy () where term = () instance (TermProxy a, TermProxy b) => TermProxy (a, b) where term = (term, term) 

I doubt such a class is very useful in any other context.

+9
source

You are looking for a class like Default . Although the semantics of what should be “default” is controversial (and I suggest you accept CA McCanns' answer to his valuable comments), you can get the Default class from the quite often used data-default package.

Grade:

 -- | A class for types with a default value. class Default a where -- | The default value for this type. def :: a 
+6
source

If you want to avoid a new class, you can define a unit in terms of the Enum class:

 unit :: Enum a => a unit = toEnum 0 

Or maybe better with the Bounded class:

 unit :: Bounded a => a unit = minBound 

Both of them give the expected result for the block type (and, most likely, for any other type of the same constructor):

 *Main> unit :: () () 

The disadvantages compared to the default data class (mentioned in another answer) is that the number of instances is less, especially there is no instance that returns [] for [a]. Also, the result is not what you can expect from some type, especially if you use minBound:

 *Main> unit :: Int -2147483648 *Main> unit :: Char '\NUL' *Main> unit :: Bool False 
+3
source

Source: https://habr.com/ru/post/897505/


All Articles