News aggregator

Well-Typed.Com: Implementing a minimal version of haskell-servant

Planet Haskell - Wed, 11/04/2015 - 5:38am

Recently, there was a question on Stack Overflow on how Servant actually works. Others were quick to suggest the Servant paper as a thorough explanation of the approach and the implementation.

As a co-author, I’m obviously happy if the paper is being read, but it’s also 12 pages long in two-column ACM style. And while it explains the implementation, it does not necessarily make it easier to start playing with the code yourself, because it only shows excerpts, and code snippets in a paper are not easily runnable.

At the same time, whenever I want to demonstrate a new concept in the Servant context, or play with new ideas, I find myself not impementing it in the main Servant code base, but rather to create a small library that is “like Servant”, built on the same principles, but much simpler, so that I have less work to do and can evaluate the ideas more quickly. I’ve talked to some other contributors, and at least some of them are doing the same. So I thought it might be useful to develop and present the code of “TinyServant”, which is not exactly tiny, but still small compared to the full Servant code base, strips away a lot of duplication and unessential extras, but is still complete enough so that we can observe how Servant works. Obviously, this still won’t explain everything that one might want to know about the implementation of Servant, but I hope that it will serve as a useful ingredient in that process.

This blog post is a somewhat revised and expanded version of my Stack Overflow answer.

This is not a general tutorial on Servant and using Servant. For learning how to use Servant, the official Servant tutorial or the general documentation section of the Servant home page are better starting points.

The code

The full code that is discussed in this post is 81 lines of Haskell and available separately.

An overview

I’m going to show the following things:

  1. How to define the web API specification language that Servant offers. We are going to define as few constructs as possible: we are not going to worry about content types (just plain text), we are not going to worry about different HTTP methods (just GET), and the only special thing we can do in routes will be that we can capture components of the path. Still, this is enough to show all relevant ideas of the Servant implementation.

  2. How to define an interpretation of the specification language. The point of Servant is that we can define many of these: an API can be interpreted as a web server (for various web backends), a web client (for various frontend languages, such as Haskell or JavaScript), a mock server, as documentation (in various formats) and more. Here, I’m going to implement an interpretation as a simplified Haskell function that can be seen as simulating a primitive web server, but without incurring any actual web dependencies.

  3. How to use TinyServant on an example. We are going to take the very first example of the Servant homepage and adapt it for our examples.


To start, here are the language extensions we’ll need:

{-# LANGUAGE DataKinds, PolyKinds, TypeOperators #-} {-# LANGUAGE TypeFamilies, FlexibleInstances, ScopedTypeVariables #-} {-# LANGUAGE InstanceSigs #-}

The first three are needed for the definition of the type-level DSL itself. The DSL makes use of type-level strings (DataKinds) and also uses kind polymorphism (PolyKinds). The use of the type-level infix operators such as :<|> and :> requires the TypeOperators extension.

The second three are needed for the definition of the interpretation. For this, we need type-level functions (TypeFamilies), some type class programming which will require FlexibleInstances, and some type annotations to guide the type checker which require ScopedTypeVariables.

Purely for documentation purposes, we also use InstanceSigs.

Here’s our module header:

module TinyServant where import Control.Applicative import GHC.TypeLits import Text.Read import Data.Time

The import of Data.Time is just for our example.

API specifications

The first ingredient is to define the datatypes that are being used for the API specifications.

data Get (a :: *) data a :<|> b = a :<|> b infixr 8 :<|> data (a :: k) :> (b :: *) infixr 9 :> data Capture (a :: *)

As I’ve said before, we define only four constructs in our simplified language:

  1. A Get a represents an endpoint of type a (of kind *). In comparison with full Servant, we ignore content types here. We need the datatype only for the API specifications. There are no directly corresponding values, and hence there is no constructor for Get.

  2. With a :<|> b, we represent the choice between two routes. Again, we wouldn’t need a constructor, but it will turn out to be useful later when we define handlers.

  3. With item :> rest, we represent nested routes, where item is the first path component and rest are the remaining components. In our simplified DSL, there are just two possibilities for item: a type-level string, or a Capture. Because type-level strings are of kind Symbol, but a Capture, defined below is of kind *, we make the first argument of :> kind-polymorphic, so that both options are accepted by the Haskell kind system. So in particular, we will be able to write both

    "person" :> Get Person


    Capture Currency :> Get Amount

    and it will be well-kinded.

  4. A Capture a represents a route component that is captured, parsed and then exposed to the handler as a parameter of type a. In full Servant, Capture has an additional string as a parameter that is used for documentation generation. We omit the string here.

Example API

We can now write down a version of the API specification from the Servant home page, adapted to our simplified DSL, and replacing the datatypes used there by actual datatypes that occur in the Data.Time library:

type MyAPI = "date" :> Get Day :<|> "time" :> Capture TimeZone :> Get ZonedTime Interpretation as server

The most interesting aspect is of course what we can do with the API. Servant defines several interpretations, but they all follow a similar pattern. We’ll define only one here, which is inspired by the interpretation as a web server.

In Servant, the serve function has the following type:

serve :: HasServer layout => Proxy layout -> Server layout -> Application

It takes a proxy for the API type (we’ll get back to that in a moment), and a handler matching the API type (of type Server layout) to an Application. The Application type comes from the excellent WAI library that Servant uses as its default backend.

Even though WAI is very simple, it is too complicated for the purposes of this post, so we’ll assume a “simulated server” of type

[String] -> IO String

This server is supposed to receive a request that is just a sequence of path components ([String]). We do not care about request methods or the request body or anything like that. And the response it just a message of type String. We ignore status codes, headers and anything else. The underlying idea is still the same though than that of the Application type used in the actual Servant implementation.

So our serve function has type

serve :: HasServer layout => Proxy layout -> Server layout -> [String] -> IO String

The HasServer class, which we’ll define below, has instances for all the different constructs of the type-level DSL and therefore encodes what it means for a Haskell type layout to be interpretable as an API type of a server.

The Proxy type is defined as follows: It’s defined as

data Proxy a = Proxy

Its only purpose is to help the GHC type checker. By passing an explicitly typed proxy such as Proxy :: Proxy MyAPI to serve, we can explicitly instantiate the serve function to a particular API type. Without the Proxy, the only occurrences of the layout parameter would be in the HasServer class constraint and as an argument of Server, which is a type family. GHC is not clever enough to infer the desired value of layout from these occurrences.

The Server argument is the handler for the API. As just stated, Server itself is a type family (i.e., a type-level function), and computes from the API type the type that the handler(s) must have. This is one core ingredient of what makes Servant work correctly.

From these inputs, we then compute the output function of type [String] -> IO String as explained above.

The Server type family

We define Server as a type family first. (Again, this is somewhat simplified compared to Servant, which defines a monad transformer type family called ServerT as part of the HasServer class and then a top-level type synonym Server in terms of ServerT.)

type family Server layout :: *

The handler for a Get a endpoint is simply an IO action producing an a. (Once again, in the full Servant code, we have slightly more options, such as producing an error with a choice of status codes.)

type instance Server (Get a) = IO a

The handler for a :<|> b is a pair of handlers, so we could just define

type instance Server (a :<|> b) = (Server a, Server b) -- preliminary

But with this definition, nested occurrences of :<|> in the API would lead to nested pairs of handlers, so we’d have to write code like

(handler1, (handler2, handler3))

which looks a bit ugly. Instead, we’re going to make :<|> equivalent to Haskell’s pair type, but with an infix constructor called :<|>, so that we can write

handler1 :<|> handler2 :<|> handler3

for a nested pair. The actual definition of Server for :<|> is then

type instance Server (a :<|> b) = Server a :<|> Server b

It remains to explain how each of the path components is handled.

Literal strings in the routes do not affect the type of the handler:

type instance Server ((s :: Symbol) :> r) = Server r

A capture, however, means that the handler expects an additional argument of the type being captured:

type instance Server (Capture a :> r) = a -> Server r Computing the handler type of the example API

If we expand Server MyAPI, we obtain

Server MyAPI ~ Server ( "date" :> Get Day :<|> "time" :> Capture TimeZone :> Get ZonedTime ) ~ Server ("date" :> Get Day) :<|> Server ("time" :> Capture TimeZone :> Get ZonedTime) ~ Server (Get Day) :<|> Server ("time" :> Capture TimeZone :> Get ZonedTime) ~ IO Day :<|> Server ("time" :> Capture TimeZone :> Get ZonedTime) ~ IO Day :<|> Server (Capture TimeZone :> Get ZonedTime) ~ IO Day :<|> TimeZone -> Server (Get ZonedTime) ~ IO Day :<|> TimeZone -> IO ZonedTime

where ~ is GHC’s syntax for type equality.

Recall that :<|> as defined is equivalent to a pair. So as intended, the server for our API requires a pair of handlers, one that provides a date of type Day, and one that, given a time zone, provides a time (of type ZonedTime). We can define the handler(s) right now:

handleDate :: IO Day handleDate = utctDay <$> getCurrentTime handleTime :: TimeZone -> IO ZonedTime handleTime tz = utcToZonedTime tz <$> getCurrentTime handleMyAPI :: Server MyAPI handleMyAPI = handleDate :<|> handleTime The HasServer class

We still have to implement the HasServer class, which looks as follows:

class HasServer layout where route :: Proxy layout -> Server layout -> [String] -> Maybe (IO String)

The task of the function route is almost like serve. Internally, we have to dispatch an incoming request to the right router. In the case of :<|>, this means we have to make a choice between two handlers. How do we make this choice? A simple option is to allow route to fail, by returning a Maybe. Then in a choice we can just try the first option, and if it returns Nothing, try the second. (Again, full Servant is somewhat more sophisticated here, and version 0.5 will have a much improved routing strategy, which probably at some point in the future deserves to be the topic of its own blog post.)

Once we have route defined, we can easily define serve in terms of route:

serve :: HasServer layout => Proxy layout -> Server layout -> [String] -> IO String serve p h xs = case route p h xs of Nothing -> ioError (userError "404") Just m -> m

If none of the routes match, we fail with a (simulated) 404. Otherwise, we return the result.

The HasServer instances

For a Get endpoint, we defined

type instance Server (Get a) = IO a

so the handler is an IO action producing an a, which we have to turn into a String. We use show for this purpose. In the actual Servant implementation, this conversion is handled by the content types machinery, and will typically involve encoding to JSON or HTML.

instance Show a => HasServer (Get a) where route :: Proxy (Get a) -> IO a -> [String] -> Maybe (IO String) route _ handler [] = Just (show <$> handler) route _ _ _ = Nothing

Since we’re matching an endpoint only, the require the request to be empty at this point. If it isn’t, this route does not match and we return Nothing.

Let’s look at choice next:

instance (HasServer a, HasServer b) => HasServer (a :<|> b) where route :: Proxy (a :<|> b) -> (Server a :<|> Server b) -> [String] -> Maybe (IO String) route _ (handlera :<|> handlerb) xs = route (Proxy :: Proxy a) handlera xs <|> route (Proxy :: Proxy b) handlerb xs

Here, we get a pair of handlers, and we use <|> for Maybe to try both, preferring the first if it matches.

What happens for a literal string?

instance (KnownSymbol s, HasServer r) => HasServer ((s :: Symbol) :> r) where route :: Proxy (s :> r) -> Server r -> [String] -> Maybe (IO String) route _ handler (x : xs) | symbolVal (Proxy :: Proxy s) == x = route (Proxy :: Proxy r) handler xs route _ _ _ = Nothing

The handler for s :> r is of the same type as the handler for r. We require the request to be non-empty and the first component to match the value-level counterpart of the type-level string. We obtain the value-level string corresponding to the type-level string literal by applying symbolVal. For this, we need a KnownSymbol constraint on the type-level string literal, but all concrete literals in GHC are automatically an instance of KnownSymbol.

The final case is for captures:

instance (Read a, HasServer r) => HasServer (Capture a :> r) where route :: Proxy (Capture a :> r) -> (a -> Server r) -> [String] -> Maybe (IO String) route _ handler (x : xs) = do a <- readMaybe x route (Proxy :: Proxy r) (handler a) xs route _ _ _ = Nothing

In this case, we can assume that our handler is actually a function that expects an a. We require the first component of the request to be parseable as an a. Here, we use the Read class, whereas in Servant, we use a special-purpose class called FromText (or FromHttpApiData in version 0.5). If reading fails, we consider the request not to match. Otherwise, we can feed it to the handler and continue.

Testing everything

Now we’re done.

We can confirm that everything works in GHCi:

GHCi> serve (Proxy :: Proxy MyAPI) handleMyAPI ["time", "CET"] "2015-11-01 20:25:04.594003 CET" GHCi> serve (Proxy :: Proxy MyAPI) handleMyAPI ["time", "12"] *** Exception: user error (404) GHCi> serve (Proxy :: Proxy MyAPI) handleMyAPI ["date"] "2015-11-01" GHCi> serve (Proxy :: Proxy MyAPI) handleMyAPI [] *** Exception: user error (404)

We now have a system that we can play with an extend and modify easily. We can for example extend the specification language by a new construct and see what we have to change. We can also make the simulation more faithful (e.g. include request bodies or query parameters). Or we can define a completely different interpretation (e.g. as a client) by following the same scheme.

Categories: Offsite Blogs

Walking a bit stream (very novice question)

Haskell on Reddit - Wed, 11/04/2015 - 4:47am

Suppose I want to walk a bit stream. In this case I am talking about a dwg reading library / app, see libdwg source file. The C version uses two indicators of where the current place in the stream is, one for byte level and one for bit level indicator and from that it reads the various variables, bits, bytes, floats, text and other, with different functions.

Two questions. 1) In Haskell how do you deal with the stream position indicator (which is state) and 2) Is this something for monads and only one bit_read function?

submitted by sixfootnix
[link] [4 comments]
Categories: Incoming News

Using github url in cabal files as dependencies

Haskell on Reddit - Wed, 11/04/2015 - 12:56am

If you have ever used bundler, you know that it is possible to specify git urls as dependencies:

gem 'nokogiri', :git => ''

I wonder if it is possible to do the same in cabal? That would be a good idea since it allows us to use projects that are not hosted on the cabal repository.

Update 1: Well, my motivation for this question is that we are working on a large Haskell project, some part of which can be open sourced. However, pushing the project to hackage doesn't sound so great for several reasons, e.g., we don't want to muddy the hackage with non mature projects and projects in early stage need a rapid dev/test/deploy cycle. Hackage only introduces an extra layer of complexity that makes this cycle slower.

I am pretty sure there are many companies out there who have the same motivation. So, if cabal has such capability, I guess we will have far more contributions from the companies which are using Haskell.

Update 2: One workaround to this problem would be to write a proxy server that acts like a fake hackage server and downloads the projects from git or wherever. One can add this fake server to the list of cabal repos such that cabal tries to download from this server (before) the hackage server. Hackage protocol seems quite simple to me, but I am not sure about the details. Does anyone has a link to the hackage protocol spec?

submitted by gtab62
[link] [18 comments]
Categories: Incoming News

Good resources to learn about datatype generic programming?

Haskell on Reddit - Tue, 11/03/2015 - 11:52pm

I'm interested in learning about using Haskell for datatype generic programming (right term?) The kind of programming used to create the Servant API.

The Servant paper describes the implementation as using a combination of type classes with type families and data kinds. Unfortunately, I've found these concepts difficult to approach and lacking in introductory material. A bit of help pointing to useful learning resources would be very useful. Any pointers?

submitted by stasiana
[link] [10 comments]
Categories: Incoming News

CFP: 25th Int'l Conf. on Compiler Construction (CC) -*new deadline*

General haskell list - Tue, 11/03/2015 - 9:22pm
[ Please forward. Apologies for any duplicates. ] ********************************************************************** CALL FOR PAPERS 25th International Conference on Compiler Construction (CC 2016) March 17-18 2016, Barcelona, Spain Co-located with CGO, HPCA, PPoPP, and EuroLLVM ********************************************************************** Important dates --------------- Abstracts due: 23 November 2015 (updated) Papers due: 30 November 2015 (updated) Author notification: 27 January 2016 Camera ready versions: 10 February 2016 Conference: 17-18 March 2016 Information ----------- The International Conference on Compiler Construction (CC) is interested in work on processing programs in the most general sense: analyzing, transforming or executing input that describes how a system operates, including traditional compiler const
Categories: Incoming News

What is your Haskell workflow? How to easily try stuff when learning?

Haskell on Reddit - Tue, 11/03/2015 - 8:29pm

I am coming from Scala, where I normally have one editor window (vi) where I edit stuff, and SBT shell where it continuously run tests / main or whatever I specify...

I would love to learn haskell but for that I am looking for some nice way how to work. Typing multiline stuff into ghci is pain, so I'd prefer something simmiliar to my scala workflow, where I have a shell / window where I type and another window where it is executed automatically.

Is there anything like it ? How do you use haskell to be productive? I would hope to avoid Emacs and have vim bindings.

submitted by fromscalatohaskell
[link] [14 comments]
Categories: Incoming News

record field names vs. -fwarn-unused-binds

glasgow-user - Tue, 11/03/2015 - 7:47pm
[ ccing haskell-cafe since while it's a ghc flag, I'll bet most compilers have an equivalent ] I really like -fwarn-unused-binds because it frequently finds bugs where I forgot to call something or use some value. If I put an export list on, it can find dead functions I forgot to delete. However, there's one case where it frequently gives false positives, and that's unused record field names. The problem is that I sometimes use record field names as documentation, but the record itself is internal and small, so I'm comfortable using positional pattern matching to open it (and in fact that can be safer, since then warn-unused-binds will make sure I used all the fields). But GHC sees these as unused functions, so it warns about them. I can work around by putting underscores on field names I haven't used yet, but it's a hassle to go edit them when I want to use them. The warning can be useful if it indicates an unused field, but since fields can also be extracted via the positional syntax it's not reliabl
Categories: Offsite Discussion

Who's hiring, HS cafe edition Re: Haskell Engineer Needed for Machine Learning Group

haskell-cafe - Tue, 11/03/2015 - 5:19pm
My team at "megacorp " is hiring. Our main project right now is a domain specific sibling to Agda / idris that runs on top of strongly consistent replicated db that we're also in the process of iterating on. A colleague and I will be at Hac Phi this weekend, and we're also helping sponsor some of the catering costs. Talk to us if you're there! On Tuesday, November 3, 2015, Kim-Ee Yeoh <ky3< at >> wrote: _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe< at >
Categories: Offsite Discussion

Joey Hess: STM Region contents

Planet Haskell - Tue, 11/03/2015 - 2:03pm

concurrent-output released yesterday got a lot of fun features. It now does full curses-style minimization of the output, to redraw updated lines with optimal efficiency. And supports multiline regions/wrapping too long lines. And allows the user to embed ANSI colors in a region. 3 features that are in some tension and were fun to implement all together.

But I have a more interesting feature to blog about... I've added the ability for the content of a Region to be determined by a (STM transaction).

Here, for example, is a region that's a clock:

timeDisplay :: TVar UTCTime -> STM Text timeDisplay tv = T.pack . show <$> readTVar tv clockRegion :: IO ConsoleRegionHandle clockRegion = do tv <- atomically . newTVar =<< getCurrentTime r <- openConsoleRegion Linear setConsoleRegion r (timeDisplay tv) async $ forever $ do threadDelay 1000000 -- 1 sec atomically . (writeTVar tv) =<< getCurrentTime return r

There's something magical about this. Whenever a new value is written into the TVar, concurrent-output automatically knows that this region needs to be updated. How does it know how to do that?

Magic of STM. Basically, concurrent-output composes all the STM transactions of Regions, and asks STM to wait until there's something new to display. STM keeps track of whatever TVars might be looked at, and so can put the display thread to sleep until there's a change to display.

Using STM I've gotten extensability for free, due to the nice ways that STM transactions compose.

A few other obvious things to do with this: Compose 2 regions with padding so they display on the same line, left and right aligned. Trim a region's content to the display width. (Handily exported by concurrent-output in a TVar for this kind of thing.)

I'm tempted to write a console spreadsheet using this. Each visible cell of the spreadsheet would have its own region, that uses a STM transaction to display. Plain data Cells would just display their current value. Cells that contain a function would read the current values of other Cells, and use that to calculate what to display. Which means that a Cell containing a function would automatically update whenever any of the Cells that it depends on were updated!

Do you think that a simple interactive spreadsheet built this way would be more than 100 lines of code?

Categories: Offsite Blogs

Language choice

Haskell on Reddit - Tue, 11/03/2015 - 1:18pm
Categories: Incoming News

JPMorgan Haskell Team is hiring

Haskell on Reddit - Tue, 11/03/2015 - 1:05pm

Hello Friends, we're hiring! We're based in Brooklyn NYC, and its an Onsite only role. Me and the team are happy to answer any questions you have on the thread.

The New Product Development (NPD) group at J.P. Morgan is seeking Haskell engineers to join our software development team. NPD focuses on high-impact and transformative technologies and solutions serving the bank and its customers, via exploratory R&D leading to rapid pilot and production deployments. Successful projects are handed off to a partner line-of-business group while blocked or infeasible projects “fail fast.” You will work with a highly creative and talented team to transform how JPM does business.

The ideal candidate will be able to work closely with a group but also drive projects independently. Developers are encouraged to interact at every level of product development. New projects arise frequently with ample opportunity for developers to spearhead new efforts. Open source contributions are encouraged.

Exposure and expertise in any of the following areas is desirable:

· Network engineering

· Cryptography engineering

· Distributed Systems

· Programming language design (e.g. compilers, interpreters, development tools)

· Database Systems

· Software assurance / verification (Model Checking (TLA+), QuickCheck, Jepsen, Coq, HOL)

· Industrial/production Haskell development

The Haskell group in NPD is focused on solutions in blockchain/distributed databases; smart-contract DSLs; REST APIs; data anonymization; probabilistic modelling; and ML tooling. We are Haskellers who enjoy leveraging ever-more-powerful abstractions and maximal expressivity to deliver robust, correct, performant, maintainable and generally kick-a$$ software.

please email me at first name dot last name at gmail dot com if you wanna learn more ( please include a CV and perhaps a cover letter), and include "functional enterprise job" in the subject. A colleague and myself will both be at Hac Phi this weekend for those who are curious and wish to learn more.

submitted by cartazio
[link] [59 comments]
Categories: Incoming News

How I Deploy Haskell Code

Haskell on Reddit - Tue, 11/03/2015 - 12:53pm
Categories: Incoming News

Coercion witnesses for opaque types?

Haskell on Reddit - Tue, 11/03/2015 - 11:57am

A lot of times, Functors (especially Monads) are opaque, with operations on them performed through fmap, (>>=), and the like. However, coerce should be performable through them without having to do, say, fmap coerce.

My thought is that modules with opaque monads could export something along the lines of either:

mCoercion :: (Coercible a b) => Coercion (M a) (M b) mCoercion = Coercion


mCoerce :: Coercion a b -> M a -> M b mCoerce Coercion = coerce

The latter is a nice alternative to the (#.) and (.#) functions in Data.Profunctor.Unsafe:

(##.) :: Coercion b c -> p a b -> p a c (.##) :: Coercion a d -> p d b -> p a b

That way, you're passing a guarantee of coercibility rather than an ignored function.

submitted by Zemyla
[link] [1 comment]
Categories: Incoming News

Monomorphism restriction error message...

Haskell on Reddit - Tue, 11/03/2015 - 10:38am

Most of the time, when I'm trying to use a feature without enabling the appropriate extension, GHC gives me a helpful message like this:

Too many parameters for class ‘MyClass’ (Use MultiParamTypeClasses to allow multi-parameter classes) In the class declaration for ‘MyClass’

With this code it's not the case:

module Main where data A = A deriving (Show) data B = B deriving (Show) someFunction = showsA A && showsA B where showsA = (== "A") . show main = return ()

This is what I would ideally expect:

'showA' is of a polymorphic type but is declared without an explicit type signature Declarations of this kind are disallowed by default for performance reasons. Possible solutions: * Add '{-# LANGUAGE NoMonomorphismRestriction #-}' to the beginning of the source file. * Add an explicit type signature: showsA :: Show a => a -> Bool

This is the actual error message:

Couldn't match expected type ‘A’ with actual type ‘B’ In the first argument of ‘showsA’, namely ‘B’ In the second argument of ‘(&&)’, namely ‘showsA B’

This is what I'd expect to come from an early alpha compiler, not a compiler in its 7.x that's about to go 8.x. When I first got this message I thought I triggered a compiler bug. Why does this have to be so bad?

submitted by lamefun
[link] [14 comments]
Categories: Incoming News

Imperative to Functional [Help] **Newbie**

Haskell on Reddit - Tue, 11/03/2015 - 10:34am

I have a Code block in imperative language (Java) , what will be the equivalent code haskell . I am completely stuck. Thanks in advance

int min = p[0]; for(int i=1; i<n; i++){ if(p[i] > min){ p[i] = min; } else{ min = p[i]; } } long result = 0; for(int i=0; i<n; i++){ result = result + (a[i]*p[i]); } return result;

The main difficulty that i am facing is how to keep track of min variable in functional way

submitted by arunlakshman
[link] [13 comments]
Categories: Incoming News

maintaining invariants with lens in nested structures

Haskell on Reddit - Tue, 11/03/2015 - 2:55am

When I am working on deeply nested structures, I sometimes want to maintain an invariant of the like of "some nested fields must be equal to one top-level field".

The best solution I found was to build something which is not actually a lens, but behaves like it as long as the invariant is maintained. Here is an example using Data.Tree (contrived):

{-# LANGUAGE RankNTypes #-} import Control.Lens import Data.Tree.Lens import Data.Tree maintaining :: Lens' a b -> Setter' a b -> Lens' a b maintaining l t = lens (view l) (\a b -> (set l b . set t b) a) subtree :: Lens' (Tree a) a subtree = root `maintaining` (branches.traverse.subtree) main :: IO () main = do let t = Node 1 [Node 1 [], Node 1 []] putStrLn . drawTree . fmap show $ t let t' = set subtree 2 t putStrLn . drawTree . fmap show $ t'

Of course, subtree is not a proper lens, because it does not obey the second lens law (setting the values enforces the invariant even if it was not enforced before - which is exactly the desired result).

Is there a better way to do this ?

submitted by le_miz
[link] [9 comments]
Categories: Incoming News