Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can some explain the reflection package API in *very* simple terms?

I'm having a hard time understanding the documentation/examples out there describing the reflection package. I'm an imperative-programming veteran but a Haskell newb. Can you walk me through a very simple introduction?

Package: https://hackage.haskell.org/package/reflection

Edit: to whoever closed this question: this is meant to be a beginner introduction to Haskell reflection. The answer below is excellent and others would be useful too, so please reopen.

like image 485
AgentLiquid Avatar asked Nov 17 '20 07:11

AgentLiquid


1 Answers

In the simplest use-case, if you have some configuration information you'd like to make generally available across a set of functions:

data Config = Config { w :: Int, s :: String }

you can add a Given Config constraint to the functions that need access to the configuration:

timesW :: (Given Config) => Int -> Int

and then use the value given to refer to the current configuration (and so w given or s given to refer to its fields):

timesW x = w given * x

With a few other functions, some that use the configuration and some that don't:

copies :: Int -> String -> String
copies n str = concat (replicate n str)

foo :: (Given Config) => Int -> String
foo n = copies (timesW n) (s given)

you can then run a computation under different configurations that you give:

main = do
  print $ give (Config 5 "x") $ foo 3
  print $ give (Config 2 "no") $ foo 4

This is similar to:

  • defining given :: Config globally, except you can run the computation under multiple configurations in the same program;

  • passing the configuration around as an extra parameter to every function, except you avoid the bother of explicitly accepting the configuration and passing it on, like:

    timesW cfg x = w cfg * x
    foo cfg n = copies (timesW cfg n) (s cfg)
    
  • using a Reader monad, but you don't have to lift everything to an awkward monad- or applicative-level syntax, like:

    timesW x = (*) <$> asks w <*> pure x
    foo n = copies <$> timesW n <*> asks s
    

The full example:

{-# LANGUAGE FlexibleContexts #-}

import Data.Reflection

data Config = Config { w :: Int, s :: String }

timesW :: (Given Config) => Int -> Int
timesW x = w given * x

copies :: Int -> String -> String
copies n str = concat (replicate n str)

foo :: (Given Config) => Int -> String
foo n = copies (timesW n) (s given)

main = do
  print $ give (Config 5 "x") $ foo 3
  print $ give (Config 2 "no") $ foo 4
like image 170
K. A. Buhr Avatar answered Oct 16 '22 12:10

K. A. Buhr