Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply a constant to all the fields of a datatype

Tags:

haskell

Let's say I have the following datatype

data A = A{x::Int,y::Int,z::Int}

Is there a way to apply 0 on all the fields to get something like this :

let a = A 0 0 0

Basically not repeating 0

The goal at the end would be to use mempty from Sum Int and do something like this :

let a = myfunction mempty :: Sum Int

and Have a == A 0 0 0

Thanks !

like image 381
Nicolas Henin Avatar asked Apr 04 '20 12:04

Nicolas Henin


People also ask

What is the data type of a field?

When you define the database fields, you select a data type for each field. The data type tells Content Manager OnDemand what kind of data can be stored in the field. For search fields, in which users enter values to construct queries For display fields, to identify the items in the document list

Can data be a constant or variable in a program?

Data can also be constant or variable within programs and functions. In a program, data values can be constant or variable. If values are variable they can be changed by the program and the user. When a program is run, the data values are held in memory whilst they are being worked on.

What data types can be declared as constants in Java?

The following example declares the Public constant conAge as an Integer and assigns it the value 34. Constants can be declared as one of the following data types: Boolean, Byte, Integer, Long, Currency, Single, Double, Date, String, or Variant.

How many types of constants can be declared in Python?

Public Const conAge As Integer = 34 Constants can be declared as one of the following data types: Boolean, Byte, Integer, Long, Currency, Single, Double, Date, String, or Variant. Because you already know the value of a constant, you can specify the data type in a Const statement. You can declare several constants in one statement.


2 Answers

There isn't one function, but you can compose Control.Monad.join with itself. You also have to unpack the 0 from mempty first, since it has type Sum Int, not Int.

let a = (join . join) A (getSum mempty)

You could then define myfunction has

myfunction = (join . join) A . getSum

and write

let a = myfunction (mempty :: Sum Int)

The more direct definition of myfunction, though, would simply be

myfunction (Sum x) = A x x x
like image 64
chepner Avatar answered Sep 23 '22 20:09

chepner


Since coincidentally Data.Default defines 0 as the default value for Int, you can use data-default-class to derive it generically with DeriveAnyClass:

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}

import Data.Default (Default(..))
import GHC.Generics (Generic(..))

data A = A { x, y, z :: Int }
  deriving (Default, Generic)

-- (def :: A) == A 0 0 0

You can make this more explicit with DerivingStrategies and enforce it with -Wmissing-deriving-strategies:

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC -Wmissing-deriving-strategies #-}

import Data.Default (Default(..))
import GHC.Generics (Generic(..))

data A = A { x, y, z :: Int }
  deriving (Default, Generic)
  deriving anyclass (Default)
  deriving stock (Generic)

-- (def :: A) == A 0 0 0

However, Data.Default is a class with no laws; it’s better used to indicate the canonical default value of a more complex configuration-like type, because its choices for primitive types are essentially arbitrary.

So if you are able to change the type a bit, you can alternatively use the generic-deriving package, in one of two ways. First, by using Sum Int as the type of the fields and deriving Semigroup and Monoid instances with generics:

{-# LANGUAGE DeriveGeneric #-}

import Generics.Deriving.Monoid

data A = A { x, y, z :: Sum Int }
  deriving (Generic)

instance Monoid A where mempty = memptydefault

instance Semigroup A where (<>) = sappenddefault

-- (mempty :: A) == A 0 0 0
-- A 1 2 3 <> A 4 5 6 == A 5 7 9

Or second—and this is my preference—by replacing the data type with a newtype over a tuple of Ints, and using DerivingVia to derive the instance via Sum Int:

{-# LANGUAGE DerivingVia #-}

newtype A = A (Int, Int, Int)
  deriving (Monoid, Semigroup) via (Sum Int, Sum Int, Sum Int)

-- (mempty :: A) == A 0 0 0
-- A 1 2 3 <> A 4 5 6 == A 5 7 9

You can recover the field names using lenses (e.g. x is _1) or by writing getters and setters manually.

like image 32
Jon Purdy Avatar answered Sep 25 '22 20:09

Jon Purdy