Great power of newtypes

NewType ( ** Newtype ** ) Is a specialized data type declaration. Such that it contains only one constructor and a field. 3r3774. 3r3r7787.` newtype Foo a = Bar a`

newtype Id = MkId Word

3r33737. 3r33737. 3r3774. 3r3r7787. 3r3774. 3r3r7787. * What is the difference from data data type? * 3r3774. 3r3r7787.

` data Foo a = Bar a`

data Id = MkId Word

3r33737. 3r33737. 3r3774. 3r3r7787. The main specificity of 3r3777. newtype [/b] consists in the fact that it consists of the same parts as its only field. More precisely, it differs from the original at the type level, but it has the same memory representation, and it is calculated strictly (not lazily). 3r3774. 3r3r7787. In short, ** newtype ** more effective due to their presentation. 3r3774. 3r3r7787. 3r3774. 3r3r7787. * Yes it means nothing to me I will use 3r3777. data [/b] * 3r3774. 3r3r7787. No, well, in the end, you can always include the extension 3r3777. -funpack-strict-fields [/b] :) for strict (not lazy) fields or point directly to

3r3r7787.

` data Id = MkId! Word`

3r33737. 3r33737. 3r3774. 3r3r7787. Yet the power of 3r3r7777. newtype [/b] not limited to the efficiency of calculations. They are much stronger! 3r366. 3r33780. 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3756. 3 roles 3r3777. newtype [/b] 3r3757. 3r3774. 3r3r7787. 3r3774. 3r3r7787.

` module Data.Id (Id ()) where`

newtype Id = MkId Word

3r33737. 3r33737. 3r3774. 3r3r7787. 3r3r7777. newtype [/b] differing from the original, internally only ** Word 3r3778. . 3r3774. 3r3r7787. But we hide the constructor **** MkId ** outside the module. 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3599. 3r3600 distribution implementation. 3r3774. 3r3r7787.

` {- # LANGUAGE GeneralizedNewtypeDeriving # -}`

newtype Id = MkId Word deriving (Num, Eq)

3r33737. 3r33737. 3r3774. 3r3r7787. Although this is not in the Haskell2010 standard, thanks to the expansion of the generic new types, you can automatically derive the behavior of 3r3777. newtype

` the same as the behavior of the inner field. In our case, the behavior `** Eq Id ** and 3r3777. Num Id [/b] the same as r3r3777. Eq Word 3r3778. and 3r3777. Num Word [/b] . 3r3774. 3r3r7787. Much more can be achieved thanks to the expansion of the refined elimination ( ** DerivingVia ** ), But more on that later. 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3599. Implementing choices 3-333600. 3r3774. 3r3r7787. Despite your own constructor, in some cases you can use your own internal representation. 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3403. Task 3r3404. 3r3774. 3r3r7787. There is a list of integers. Find the maximum and total amount for just one pass through the list. 3r3774. 3r3r7787. And do not use the 3r3777 packages. foldl 3r3778. and 3r3777. folds [/b] . 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3403. The typical answer is 3r3404. 3r3774. 3r3r7787. Of course, 3r3777. fold [/b] ! :)

3r3r7787.

` foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b`

{- 3r3787. - instance Foldable[]3r3r7787. foldr :: (a -> b -> b) -> b ->[a]-> b

-} 3r3787. 3r33737. 3r33737. 3r3774. 3r3r7787. And, the final function is described as:

3r3r7787.

` aggregate ::[Integer]-> (Maybe Integer, Integer)`

aggregate = foldr

(el (m, s) -> (Just el `max` m, el + s))

(Nothing, 0)

3r3r7787. {- 3r3787. ghci> aggregate[1, 2, 3, 4]3r3r7787. (Just ? 10)

-} 3r3787. 3r33737. 3r33737. 3r3774. 3r3r7787. If you look closely, you can see similar operations on both sides: ** Just el `max` m ** and 3r3777. el + s [/b] . In both cases - mapping and binary operation. And the empty elements - ** Nothing ** and 3r3777. 0 [/b] . 3r3774. 3r3r7787. Yes, these are monoids! 3r3774. 3r3r7787. 3r33432. 3r33333. Monoid and Semigroup more details [/b] 3r33434. A semigroup is a property of an associative binary operation

3r3r7787.

` x ⋄ (y ⋄ z) == (x ⋄ y) ⋄ z`

3r33737. 3r33737. 3r3774. 3r3r7787. A monoid is a property of an associative operation (that is, a semigroup)

3r3r7787.

` x ⋄ (y ⋄ z) == (x ⋄ y) ⋄ z`

3r33737. 3r33737. 3r3774. 3r3r7787. which has an empty element that does not change any element, either to the right or to the left

3r3r7787.

` x ⋄ empty == x == empty ⋄ x`

3r33737. 3r33737. 3r3774. 3r3r7787. 3r33788. 3r33788. 3r3774. 3r3r7787. Both ** max ** and 3r3777. (+) 3r3778. - associative, both have empty elements - 3r3777. Nothing [/b] and 3r3777. 0 [/b] . 3r3774. 3r3r7787. And the union of the mapping of monoids along with the convolution is the same ** Foldable ** (coagulability)! 3r3774. 3r3r7787. 3r33432. 3r33333. Foldable more details [/b] 3r33434. Recall the definition of coagulability:

3r3r7787.

` class Foldable t where`

foldMap :: (Monoid m) => (a -> m) -> t a -> m

3r33737. 3r33737. 3r3774. 3r3r7787. 3r33788. 3r33788. 3r3774. 3r3r7787. Let's apply the rollover behavior to ** max ** and 3r3777. (+) 3r3778. . We will be able to organize no more than one implementation of the monoid 3r3r7777. Word 3r3778. . It's time to use the implementation of choice 3r3r7777. newtype [/b] ! 3r3774. 3r3r7787.

` {- # LANGUAGE GeneralizedNewtypeDeriving # -}`

3r3r7787. - already in Data.Semigroup & Data.Monoid

3r3r7787. newtype Sum a = Sum {getSum :: a}

deriving (Num, Eq, Ord)

3r3r7787. instance (Num a, Ord a) => Semigroup (Sum a) where

( <>) = (+)

Instance (Num a, Ord a) => Monoid (Sum a) where

Mempty = Sum 0

Newtype Max a = Max {getMax :: a}

Ord)

Instance (Num a, Ord a) => Semigroup (Max a) where

(3r3304.

3r3333733. 3r3774. 3r3r7787. It is necessary to make a remark. 3r3774. 3r3r7787. The fact is that in order to be a monoid for the data type ** Max a ** , we need a minimal element, that is, in order for an empty element to exist. So, a monoid can only be a limited 3r3777. Max a [/b] . 3r3774. 3r3r7787. 3r33432. 3r33333. Theoretically correct monoid of the maximum element [/b] 3r33434.

` newtype Max a = Max a`

Instance Ord a => Semigroup (Max a)

Instance Bounded a => Monoid (Max a)

3r33737. 3r33737. 3r3774. 3r3r7787. 3r33788. 3r33788. 3r3774. 3r3r7787. So somehow we have to convert our data type so that an empty element appears and we can use clotting. 3r3774. 3r3r7787.

` - already in Prelude`

data Maybe a = Nothing | Just a 3r3r7787. 3r3r7787. Instance Semigroup a => Semigroup (Maybe a) where

Nothing <> b = b

b <> Nothing = b

(Just a) <> (Just b) = Just (a <> b) 3r3787. 3r3r7787. Instance Semigroup a => Monoid (Maybe a) where

mempty = Nothing

3r3r7787. - ------

Instance Functor Maybe where

fmap _ Nothing = Nothing

fmap f (Just b) = Just (f b)

3r33737. 3r33737. 3r3774. 3r3r7787. Conjugate element ** Maybe ** turns a semigroup into a monoid! 3r3774. 3r3r7787. 3r33432. 3r33333. Liberalization of restrictions in fresh versions of GHC [/b] 3r33434. Even in GHC 8.? a monoid was required in a restriction of type

3r3r7787.

` Instance Monoid a => Monoid (Maybe a)`

3r33737. 3r33737. 3r3774. 3r3r7787. which means we needed another newType: 3r3774. 3r3r7787.

` - already in Data.Semigroup & Data.Monoid`

3r3r7787. newtype Option a = Option {getOption :: Maybe a}

deriving (Eq, Ord, Semigroup)

3r3r7787. Instance (Ord a, Semigroup a) => Monoid (Option a) where

mempty = Option Nothing

3r33737. 3r33737. 3r3774. 3r3r7787. And it is much simpler already in GHC 8.? where only a semigroup is needed to restrict the type, and even there is no need to create the type Option. 3r3774. 3r3r7787.

` Instance Semigroup a => Monoid (Maybe a)`

3r33737. 3r33737. 3r3774. 3r3r7787. 3r33788. 3r33788. 3r3774. 3r3r7787. 3r3403. The answer is using a 3r3404 rollover. 3r3774. 3r3r7787. Well, now let's update the code using the rollover and arrows. 3r3774. 3r3r7787. Recall that (.) Is just a functional composition:

3r3r7787.

` (.) :: (b -> c) -> (a -> b) -> a -> c`

f. g = x -> f (g x)

3r33737. 3r3774. 3r3r7787. And remember that ** fmap ** - the functor: 3r3774. 3r3r7787.

` fmap :: Functor f => (a -> b) -> f a -> f b `

3r33737. 3r3774. 3r3r7787. and its implementation for ** Maybe ** described slightly above. 3r3774. 3r3r7787. 3r33432. 3r33333. Arrow more details 3r3778. 3r33434. Arrows are the properties of some functions that allow you to work with them flowchart. 3r3774. 3r3r7787. More detail, you can see here: 3r3r438. Arrows: A General Interface to Computation

3r3774. 3r3r7787. In our case, we use the arrows of the function 3r3774. 3r3r7787. That is

3r3r7787.

` Instance Arrow (->) `

3r33737. 3r3774. 3r3r7787. We will use the functions: 3r3774. 3r3r7787.

` (***) :: Arrow a => a b c -> a b 'c' -> a (b, b ') (c, c')`

(&&&) :: Arrow a => a b c -> a b c '-> a b (c, c')

3r33737. 3r3774. 3r3r7787. For our case 3r3728. ` a b c == (->) b c == b -> c `

3r33737. 3r3774. 3r3r7787. And, accordingly, the signature of our functions is reduced to: 3r3774. 3r3r7787.

` (***) :: (b -> c) -> (b '-> c') -> ((b, b ') -> (c, c')) 3r3787. (&&&) :: (b -> c) -> (b -> c ') -> (b -> (c, c')) 3r33232. 3r33737. 3r3774. 3r3r7787. Or in very simple words, the function 3r3r7777. (***) 3r3778. combines two functions with one argument (and one output type) into a function with the operation of a pair of arguments at the input, and at the output, respectively, a pair of output types. 3r3774. 3r3r7787. Function `** (&&&) 3r3778. - This is a trimmed version of **** (***) 3r3778. where the type of the input arguments of the two functions is the same, and at the input we do not have a pair of arguments, but one argument. 3r3774. 3r3r7787. 3r33788. 3r33788. 3r3774. 3r3r7787. Total, unifying function acquired the form:**

3r3r7787.

` import Data.Semigroup`

import Data.Monoid

import Control.Arrow

3r3r7787. aggregate ::[Integer]-> (Maybe Integer, Integer)

aggregate = 3r3787. (fmap getMax *** getSum)

. (foldMap (Just. Max &&& Sum))

3r3r7787. {- 3r3787. - for GHC ???r3r3787. aggregate = 3r3787. (fmap getMax. getOption *** getSum)

. (foldMap (Option. Just. Max &&& Sum))

-} 3r3787. 3r33737. 3r33737. 3r3774. 3r3r7787. It turned out very briefly! 3r3774. 3r3r7787. But, it is still tiring to wrap and wrap data from nested types! 3r3774. 3r3r7787. You can still cut, and we will help resource-free forced conversion! 3r3774. 3r3r7787. 3r3774. 3r3r7787.

` Safe non-resource forced conversion and the role of types 3r3757. 3r3774. 3r3r7787. There is a function from the package `** Unsafe.Coerce ** - 3r3777. unsafeCoerce

` 3r3774. 3r3r7787.`

` import Unsafe.Coerce (unsafeCoerce)`

unsafeCoerce :: a -> b

3r33737. 3r33737. 3r3774. 3r3r7787. The function forcibly converts type unsafe: from 3r3777. a

` in 3r3777. b [/b] . 3r3774. 3r3r7787. In essence, the function is magic, it tells the compiler to read data of the type `** a ** type 3r3777. b [/b] , without taking into account the consequences of this step. 3r3774. 3r3r7787. It can be used to convert nested types, but you need to act very carefully. 3r3774. 3r3r7787. In 201? the revolution took place with 3r3777. newtype [/b] , namely appeared safe resource-free forced conversion! 3r3774. 3r3r7787.

` import Data.Coerce (coerce)`

coerce :: Coercible a b => a -> b

3r33737. 3r33737. 3r3774. 3r3r7787. This feature has opened a new era in working with 3r3777. newtype [/b] . 3r3774. 3r3r7787. Forced converter ** Coercible ** works with types that have the same structure in memory. It looks like a class-type, but in fact GHC converts types during compilation and it is impossible to independently determine instances. 3r3774. 3r3r7787. Function ** Data.Coerce.coerce ** allows us to convert types without resources, but for this we need to have access to type constructors. 3r3774. 3r3r7787. Now simplify our function:

3r3r7787.

` import Data.Semigroup`

import Data.Monoid

import Control.Arrow

import Data.Coerce

3r3r7787. aggregate ::[Integer]-> (Maybe Integer, Integer)

aggregate = 3r3787. coerce. (foldMap (Just. Max &&& Sum))

3r3r7787. - coerce :: (Maybe (Max Integer), Sum Integer) -> (Maybe Integer, Integer)

3r33737. 3r33737. 3r3774. 3r3r7787. We avoided the routine of pulling out nested types; we did it without spending resources with just one function. 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3599. The roles of nested data types are 3r33600. 3r3774. 3r3r7787. With function 3r3777. coerce 3r3778. we can force any nested types to convert. 3r3774. 3r3r7787. But should this feature be so widely used? 3r3774. 3r3r7787.

` - already in Data.Ord`

- Down a - reversed order

newtype Down a = Down a

deriving (Eq, Show)

3r3r7787. Instance Ord a => Ord (Down a) where

compare (Down x) (Down y) = y `compare` x

3r3r7787. import Data.List (sort)

- Sorted

data Sorted a = Sorted[a]3r3r7787. deriving (Show, Eq, Ord)

3r3r7787. fromList2Sorted :: Ord a =>[a]-> Sorted a

fromList2Sorted = Sorted. sort

3r3r7787. - minimum: O (1)! 3r3r7787. minView :: Sorted a -> Maybe a

minView (Sorted[]) = Nothing

minView (Sorted (a: _)) = Just a

3r33737. 3r33737. 3r3774. 3r3r7787. Semantically, it is absurd to convert to 3r3777. Sorted a [/b] from 3r3777. Sorted (Down a) [/b] . 3r3774. 3r3r7787. However, you can try:

3r3r7787.

` ghci> let h = fromList2Sorted[1,2,3]:: Sorted Int`

ghci> let hDown = fromList2Sorted $ fmap Down[1,2,3]:: Sorted (Down Int)

ghci> minView h

Just (Down 1)

ghci> minView (coerce h :: Sorted (Down Int))

Just (Down 1)

3r3r7787. ghci> minView hDown

Just (Down 3)

3r33737. 3r33737. 3r3774. 3r3r7787. All anything, but the correct answer - 3r3777. Just (Down 3) 3r3778. . 3r3774. 3r3r7787. It was in order to cut off the wrong behavior that type roles were introduced. 3r3774. 3r3r7787.

` {- # LANGUAGE RoleAnnotations # -}`

3r3r7787. type role Sorted nominal

3r33737. 3r33737. 3r3774. 3r3r7787. Let's try now:

3r3r7787.

` ghci> minView (coerce h :: Sorted (Down Int))`

error: Couldn't match type ‘Int’ with ‘Down Int’

arising from a use of coerce ’3r3787. 3r33737. 3r33737. 3r3774. 3r3r7787. Much better! 3r3774. 3r3r7787. 3r3774. 3r3r7787. In total there are 3 roles ( ** Type role ** ):

3r3r7787. 3r3693. 3r3r7787. 3r3704. 3r3r7777. representational 3r3778. - equivalent, if the same presentation

3r3r7787. 3r3704. 3r3r7777. nominal [/b] - must have exactly the same type

3r3r7787. 3r3704. 3r3r7777. phantom [/b] - does not depend on real content. Equivalent to anything

3r3r7787.

3r3774. 3r3r7787. In most cases, the compiler is smart enough to reveal the role of the type, but it can be helped. 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3756. Specified deducing behavior DerivingVia

` Safe non-resource forced conversion and the role of types 3r3757. 3r3774. 3r3r7787. There is a function from the package `** Unsafe.Coerce ** - 3r3777. unsafeCoerce

` 3r3774. 3r3r7787.`

` import Unsafe.Coerce (unsafeCoerce)`

unsafeCoerce :: a -> b

3r33737. 3r33737. 3r3774. 3r3r7787. The function forcibly converts type unsafe: from 3r3777. a

` in 3r3777. b [/b] . 3r3774. 3r3r7787. In essence, the function is magic, it tells the compiler to read data of the type `** a ** type 3r3777. b [/b] , without taking into account the consequences of this step. 3r3774. 3r3r7787. It can be used to convert nested types, but you need to act very carefully. 3r3774. 3r3r7787. In 201? the revolution took place with 3r3777. newtype [/b] , namely appeared safe resource-free forced conversion! 3r3774. 3r3r7787.

` import Data.Coerce (coerce)`

coerce :: Coercible a b => a -> b

3r33737. 3r33737. 3r3774. 3r3r7787. This feature has opened a new era in working with 3r3777. newtype [/b] . 3r3774. 3r3r7787. Forced converter ** Coercible ** works with types that have the same structure in memory. It looks like a class-type, but in fact GHC converts types during compilation and it is impossible to independently determine instances. 3r3774. 3r3r7787. Function ** Data.Coerce.coerce ** allows us to convert types without resources, but for this we need to have access to type constructors. 3r3774. 3r3r7787. Now simplify our function:

3r3r7787.

` import Data.Semigroup`

import Data.Monoid

import Control.Arrow

import Data.Coerce

3r3r7787. aggregate ::[Integer]-> (Maybe Integer, Integer)

aggregate = 3r3787. coerce. (foldMap (Just. Max &&& Sum))

3r3r7787. - coerce :: (Maybe (Max Integer), Sum Integer) -> (Maybe Integer, Integer)

3r33737. 3r33737. 3r3774. 3r3r7787. We avoided the routine of pulling out nested types; we did it without spending resources with just one function. 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3599. The roles of nested data types are 3r33600. 3r3774. 3r3r7787. With function 3r3777. coerce 3r3778. we can force any nested types to convert. 3r3774. 3r3r7787. But should this feature be so widely used? 3r3774. 3r3r7787.

` - already in Data.Ord`

- Down a - reversed order

newtype Down a = Down a

deriving (Eq, Show)

3r3r7787. Instance Ord a => Ord (Down a) where

compare (Down x) (Down y) = y `compare` x

3r3r7787. import Data.List (sort)

- Sorted

data Sorted a = Sorted[a]3r3r7787. deriving (Show, Eq, Ord)

3r3r7787. fromList2Sorted :: Ord a =>[a]-> Sorted a

fromList2Sorted = Sorted. sort

3r3r7787. - minimum: O (1)! 3r3r7787. minView :: Sorted a -> Maybe a

minView (Sorted[]) = Nothing

minView (Sorted (a: _)) = Just a

3r33737. 3r33737. 3r3774. 3r3r7787. Semantically, it is absurd to convert to 3r3777. Sorted a [/b] from 3r3777. Sorted (Down a) [/b] . 3r3774. 3r3r7787. However, you can try:

3r3r7787.

` ghci> let h = fromList2Sorted[1,2,3]:: Sorted Int`

ghci> let hDown = fromList2Sorted $ fmap Down[1,2,3]:: Sorted (Down Int)

ghci> minView h

Just (Down 1)

ghci> minView (coerce h :: Sorted (Down Int))

Just (Down 1)

3r3r7787. ghci> minView hDown

Just (Down 3)

3r33737. 3r33737. 3r3774. 3r3r7787. All anything, but the correct answer - 3r3777. Just (Down 3) 3r3778. . 3r3774. 3r3r7787. It was in order to cut off the wrong behavior that type roles were introduced. 3r3774. 3r3r7787.

` {- # LANGUAGE RoleAnnotations # -}`

3r3r7787. type role Sorted nominal

3r33737. 3r33737. 3r3774. 3r3r7787. Let's try now:

3r3r7787.

` ghci> minView (coerce h :: Sorted (Down Int))`

error: Couldn't match type ‘Int’ with ‘Down Int’

arising from a use of coerce ’3r3787. 3r33737. 3r33737. 3r3774. 3r3r7787. Much better! 3r3774. 3r3r7787. 3r3774. 3r3r7787. In total there are 3 roles ( ** Type role ** ):

3r3r7787. 3r3693. 3r3r7787. 3r3704. 3r3r7777. representational 3r3778. - equivalent, if the same presentation

3r3r7787. 3r3704. 3r3r7777. nominal [/b] - must have exactly the same type

3r3r7787. 3r3704. 3r3r7777. phantom [/b] - does not depend on real content. Equivalent to anything

3r3r7787.

3r3774. 3r3r7787. In most cases, the compiler is smart enough to reveal the role of the type, but it can be helped. 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3756. Specified deducing behavior DerivingVia

` 3r3774. 3r3r7787. Thanks to the language extension `** DerivingVia ** , improved distribution role 3r3777. newtype [/b] . 3r3774. 3r3r7787. Beginning with GHC 8.? which was recently released, this new extension has appeared. 3r3774. 3r3r7787.

` {- # LANGUAGE DerivingVia # -}`

newtype Id = MkId Word deriving (Semigroup, Monoid) via Max Word

3r33737. 3r33737. 3r3774. 3r3r7787. As you can see, the behavior of the type is automatically derived thanks to the clarification of how to output. 3r3774. 3r3r7787. 3r3r7777. DerivingVia [/b] can be applied to any type that supports 3r3r7777. Coercible [/b] and what is important - completely without the consumption of resources! 3r3774. 3r3r7787. Even more, 3r3r7777. DerivingVia [/b] can be applied not only to 3r3r7777. newtype [/b] , but also to any isomorphic types, if they support generics ** Generics 3r3778. and forced conversion [b] Coercible ** . 3r3774. 3r3r7787. 3r3774. 3r3r7787. 3r3756. Conclusions 3r3757. 3r3774. 3r3r7787. Types ** newtype ** - a powerful force that greatly simplifies and improves the code, eliminates the routine and reduces the consumption of resources. 3r3774. 3r3r7787. 3r3774. 3r3r7787. * Original translation * : The Great Power of newtypes * (Hiromi Ishii) * 3r3774. 3r3r7787. 3r3774. 3r3r7787. * 3r3r7777. P.S. 3r3778. I think, after this article,[a]? published over a year ago. Article 3r3779. The magic of a newtype in Haskell*

about new types will be a little clearer! 3r33788. 3r3r7787. 3r3r7787.

3r3r7787. 3r33788.

It may be interesting

#### weber

Author**15-10-2018, 04:11**

Publication Date
#### Functional Programming / Programming / Haskell

Category- Comments: 0
- Views: 328

looking for the best social traffic services to buy online? look no further. Want to capitalize on the world’s obsession with social media? Buy social traffic that is driven to your website or blog from the most popular social media platforms including Facebook, Instagram, Twitter and more! Activities on Facebook will be fruitful when you, along with your other activities on other social networks and of course your website, also benefit from the facilities and potentials hidden in Facebook. Facebook alone cannot be a factor in the success of your business. So, you should use Facebook as a bridge to acquaint your audience with your main sales channel, which could be another social network or your website. Once you have successfully attracted your users on a global scale, it is time to use its practical tools to attract international customers. The essence of Facebook is free and building and running a business page on it will not cost you anything. But once you get to the right place on the network, the cost of smart advertising may seem very reasonable.