Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to emulate a function using your own data type?

Is it possible to emulate a function with your own data type with some GHC extension? What I want to do is e.g.

(imaginary syntax)

data MyFunc = MyFunc String (Int->Int)

instance (Int->Int) MyFunc where
    ($) (MyFunc _ f) i = f i

inc = MyFunc "increment" (1+)

test = inc 1

I.e. data that carries some meta-information with it and can be pattern matched, but which can still be called like a regular function. Now, I know that I could define my own infix operator like $$ and call inc $$ 1, but being able to use the regular function call syntax would be very useful in embedded DSLs.

like image 204
shang Avatar asked Jun 26 '11 08:06

shang


People also ask

Can we create our own data type in Java?

You can create a new class which has specific fields. If you need exact size of fields you can use byte arrays. class Data { public byte[] dataA = new byte[1]; public byte[] dataB = new byte[2]; public byte[] dataC = new byte[7]; ... }

Are functions data types?

function is a StreamBase data type and a reserved keyword. Use a constructor for the function data type to create a custom expression language function whose components are built-in functions, math operators, and even other functions.

Which of the following functions can be used to learn the data type used?

Hence the correct answer is sizeof.

How do you create a new data type?

To create a user-defined data type. In Object Explorer, expand Databases, expand a database, expand Programmability, expand Types, right-click User-Defined Data Types, and then click New User-Defined Data Type.


2 Answers

Yes, it can be done to a limited extent.

But first we'll need

{-# LANGUAGE Rank2Types #-}

Let's define

data M a b = M { name :: Int -> String -> String, eval :: a -> b }

I'm adding more structure to your names so I can get nicer show support. ;)

Then lets define a class:

class Magic m where
    magic :: M a b -> m a b

instance Magic M where
    magic = id

instance Magic (->) where
    magic (M _ f) = f

Now, consider the type:

type MyFunc a b = forall m. Magic m => m a b

The result type of magic is either (a -> b) or a M a b.

So it can be used as a member of MyFunc. Now, this type is somewhat unsatisfying, because you can't make instances dispatch on it, but it does mean that

inc :: MyFunc Int Int
inc = magic (M (const (showString "inc")) (+1))

test :: Int
test = inc 1

works just fine.

We can even make a rather nice way to show them. Even though we can't use show on MyFunc, we can define it for M.

instance Show (M a b) where
    showsPrec d (M s _) = s d

Then we can make a function we can apply to M a b (and by extension any MyFunc) to get out an M a b.

m :: M a b -> M a b
m = id

and we can define a special combinator to show MyFuncs:

showM :: MyFunc a b -> String
showM f = show (m f)

Then we can play. We can define compositions of MyFuncs.

infixr 9 .#
(.#) :: MyFunc b c -> MyFunc a b -> MyFunc a c
f .# g = magic (M 
    (\d -> showParen (d > 9) $ showsPrec 10 (m f) . 
                               showString " . " . 
                               showsPrec 9 (m g)) 
    (f . g))

inc2 :: MyFunc Int Int
inc2 = inc .# inc

test2 :: Int
test2 = inc2 1

bar, baz :: String
bar = showM inc
baz = showM inc2

And because I gave enough structure to the names, we even get correct parenthesization for more complicated compositions, without needless parentheses.

*Main> showM $ inc2 .# inc
"(inc . inc) . inc"

*Main> showM $ inc .# inc2
"inc . inc . inc"

But remember, you won't be able to define any instances for MyFunc, since it can only be a type, and not a newtype. In order to define instances you'll have to define them on M, and then use m to convert to that type so that implicit dispatch has a type to grab onto.

Because of the rank 2 type, if you use these heavily in local contexts, you may also want to turn on NoMonoLocalBinds and/or NoMonomorphismRestriction.

like image 52
Edward Kmett Avatar answered Nov 12 '22 16:11

Edward Kmett


No, the syntax f e cannot be overloaded. The f has to have type S -> T.

But you can still do a lot with EDSLs if you do a deep embedding, i.e., you let your functions build syntax trees instead of computing.

like image 33
augustss Avatar answered Nov 12 '22 14:11

augustss