
Towards Idris Version 1.0 - yomritoyj
http://www.idris-lang.org/towards-version-1-0/
======
chriswarbo
Any ideas why the effect system may be deprecated in favour of the state
machine/indexed monads system? To me, they seem to be fulfilling two different
requirements: algebraic effects let us call 'operations' in an expression by
writing placeholder values, track the usage of such operations in the type,
and plug in the implementation afterwards. For example, we can write "print"
as a placeholder, give it a "StdOut" effect type, and provide a production
implementation which writes to the program's stdout, a test implementation
which produces a normal String value for us to check, a remote implementation
which writes to a WebSocket, etc.

The state machine stuff seems to mostly be concerned with using types to keep
track of state, in terms of which actions are available or unavailable, e.g.
you can't close a file unless it's open, you can't read from a file unless
it's open, you can't run an expression unless it closes all of its files, etc.

There's certainly overlap, but I'm not sure whether one subsumes the other.

~~~
pseudonom-
Extensible effects arise from combining a free monad with an open union of
functors. Using an indexed free monad with indexed functors instead is a
generalization that provides more expressive power.

Intuitively, I like to think of it as:

\- Extensible effects describe what we permit (read from console, print to
console) \- Indexed monads describe what we demand (you must auth before you
can access db, you must open file before you can read it)

I'm actually working on doing a version of this in Haskell. You can see Oleg's
version of it here:
[http://okmij.org/ftp/Haskell/extensible/ParamEff1.hs](http://okmij.org/ftp/Haskell/extensible/ParamEff1.hs)

I may have a more informed opinion after I read the states-all-the-way paper.

~~~
bjz_
Any more papers/resources I can look at to get more context on the indexed
monads vs effect systems comparison? Are they as composable as effects - ie.
how do they solve the problems with monad transformers, etc?

~~~
pseudonom-
I think the proposal people are making is better thought of as indexed monads
and effects rather than indexed monads or effects.

Normal extensible effects looks like:

    
    
        data Union :: [Type] -> Type -> Type where
          ...
    
        data Free :: (Type -> Type) -> Type -> Type where
          ...
        
        type Eff fs = Free (Union fs)
        
        class Inject f fs where
          inj :: f a -> Union fs a
        
        data File :: Type -> Type where
          Open :: FilePath -> File ()
          Close :: FilePath -> File ()
        
        send :: (Inject f fs) => f a -> Eff fs a
        
        -- The inferred type would be more general
        openClose :: Eff '[File] ()
        openClose = do
          send (Open "foo.txt")
          send (Close "foo.txt")
    

You can then generalize this by also indexing everything:

    
    
        data HList :: [Type] -> Type where
          Nil :: HList '[]
          (:>) :: a -> HList as -> HList (a ': as)
    
        data Union :: HList fs -> HList is -> HList is -> Type -> Type where
          ...
    
        data Free :: (is -> is -> Type -> Type) -> is -> is -> Type -> Type where
          ...
        
        type Eff fs = Free (Union fs)
        
        class Inject f i o fs is os where
          inj :: f i o a -> Union fs is os a
        
        data FileStatus = Open | Closed
        
        data File :: FileStatus -> FileStatus -> Type -> Type where
          Open :: FilePath -> File 'Closed 'Open ()
          Close :: FilePath -> File 'Open 'Closed ()
        
        send :: (Inject f i o fs is os) => f i o a -> Eff fs is os a
        
        -- The inferred type would be more general
        openClose :: Eff (File ':> 'Nil) ('Closed ':> 'Nil) ('Closed ':> Nil) ()
        openClose = do
          send (Open "foo.txt")
          send (Close "foo.txt")
    
    

Does that help at all?

~~~
bjz_
Yes, that helps a ton! So it's simply combining extensible effects with state
transitions to help you be more specific about the legal ways to sequence
effectful operations.

The proliferation of type params looks intimidating from a user perspective
though - is there some way to make it easier on folks? Would it look nicer in
a language with row polymorphism perhaps?

------
tupshin
Is anybody still thinking about Idris and HoTT?
[https://github.com/fmota/HoTT-
Idris/blob/master/README.md](https://github.com/fmota/HoTT-
Idris/blob/master/README.md) I don't see anything more recent than the 2014
discussions.

------
chriswarbo
Sounds good!

I played with Idris quite a bit in the early days. I started spending more
time in Coq around the time Idris gained its proof search mechanisms (I'm
still not sure how they work!), but Idris has always been a more 'realistic'
language for development (as opposed to proof engineering).

I think I spoiled myself with dependent types, as all of my Haskell projects
seem to hit a wall which dependent types can trivially solve (e.g. calculating
a type or a TypeRep based on incoming JSON data)

~~~
hood_syntax
Dependent types are the big win for me as well, even though I'm pretty
inexperienced with both Haskell and Idris. I've heard LiquidHaskell thrown
around when people talk about dependent types, have you looked into that
before?

~~~
chriswarbo
As far as I'm aware, LiquidTypes focus on very simple use cases, like length-
indexed Vector types and such.

I don't think it can manage "full" dependent types, for example situations I
often find myself in where I want to calculate a type from incoming data, e.g.
something like:

    
    
        parseJSON : String -> Maybe JSON
        parseJSON = ...
    
        parseMyData : JSON -> Maybe MyData
        parseMyData = ...
    
        HasSomeProperty : MyData -> Type
        HasSomeProperty x = case x of
          MyCase1 -> ...
          ...
    
        someProcessing : (x : MyData) -> HasSomeProperty x -> ResultOfProcessing x
        someProcessing x p = ...
    

Often, we write "HasSomeProperty" such that it performs some arbitrary
calculation to decide between returning the unit type ("does have this
property") or returning the empty type ("doesn't have the property, or can't
tell"). Whenever we need to provide a value of type "HasSomeProperty x", we
just put a unit value and the type-checker will enforce that our arbitrary
calculation resulted in a unit type. We can then use that property to access a
bunch of functionality which the compiler would otherwise forbid us from
using.

This sort of code is trivial in a dynamically typed language: there's no
requirement to prove _anything_ , so we don't need any "HasSomeProperty x"
values at all: we just go ahead and use whatever code we like, and hope that
we didn't mess something up.

We hit problems when we want to write our program in a language like Haskell
with a (relatively) weak type system: the type system quite rightly forbids us
from writing the unsafe version that dynamic languages would accept, but the
language isn't expressive enough for us to (easily) encode the proofs required
to convince the type checker that what we're doing is safe.

~~~
clusmore
>This sort of code is trivial in a dynamically typed language: there's no
requirement to prove anything ... we just go ahead and use whatever code we
like, and hope that we didn't mess something up. >the [Haskell] type system
quite rightly forbids us from writing the unsafe version that dynamic
languages would accept

As somebody with familiarity with Haskell in the small but not in large
applications, is it not similarly trivial to write in Haskell with the same
level of safety that dynamic languages give you (i.e. explosion at runtime)?

Consider as an example the following safe lookup function (standard Haskell)

    
    
      lookup :: Eq a => a -> [(a, b)] -> Maybe b
      lookup _ [] = Nothing
      lookup x ((a, b):abs)
        | a == x = Just b
        | otherwise = lookup x abs
    

and the following unsafe lookup function

    
    
      lookup :: Eq a => a -> [(a, b)] -> b
      lookup x ((a, b):abs)
        | a == x = b
        | otherwise = lookup x abs
    

How is the latter any worse than lookup in a dynamically-typed language where
you are assuming the lookup will succeed (and hence don't write any error
handling logic)? I know this sort of code is frowned upon in Haskell, but it
can be done.

~~~
tome
> How is the latter any worse than lookup in a dynamically-typed language

Presumably you mean "better", not "worse". Well, it's better because you will
(or should) get a compiler warning (or ideally an error) about the latter
version.

~~~
clusmore
I agree it's better, you will get a compiler warning about a partial function.
I did actually mean worse though. The GP at least to me implied that Haskell
(for cases like this) sits in the lowlands between Idris (and other
dependently-typed languages) and dynamically-typed languages. Idris deals with
the problem "the right way" by helping you guarantee that you deal with
dynamic objects in a compile-time-guaranteed safe way, at the cost of some
hassle of proving it is. Dynamically-typed languages deal with the problem
"the practical way" by letting you pretend its safe so you don't have to go
through the hassle of proving it is, at the cost of runtime safety. I think
Haskell can also let you do this, it just feels wrong to do it as a Haskell
programmer.

~~~
chriswarbo
You're absolutely right that various hacks can be employed in Haskell; as well
as missing branches, we can also exploit laziness to provide "undefined" or
"loop = loop" expressions which, if we're right, won't ever be evaluated.

I didn't mean to imply that dynamic languages are "better" because they allow
unchecked combinations of everything with everything else. Although I also
didn't mean to imply that they're _strictly_ "worse", precisely because there
are things we can express easily in dynamic languages which take effort to
reproduce in something like Haskell.

My main reason to mention dynamic languages was as motivation for why you
might want to write such code in the first place: using dependent types to,
say, prove Euclid's theorem of the infinitude of primes, would probably not
motivate many software developers to give Idris a try. Examples like the type-
safe printf mentioned in a sibling comment would presumably be much better
motivators: we compute a type based on the format string, so providing a
string like "Hello world %f %s !" will produce a type `Float -> String ->
String` which accepts the required Float and String parameters, then returns
the resulting String.

~~~
clusmore
Thanks for clarifying.

Off-topic, but related to undefined in Haskell, I love holes in Idris as a way
to represent incomplete programs. I'd love if it somebody could take them one
step further and have it so that if a hole is evaluated at runtime, a prompt
came up and said "Well this is the input, what do you think the output should
be?". You type it in, the program keeps going and a unit test is generated and
put away somewhere for you to make sure that later when you implement it, you
can help verify that you're doing it right.

~~~
dllthomas
> I'd love if it somebody could take them one step further and have it so that
> if a hole is evaluated at runtime, a prompt came up and said "Well this is
> the input, what do you think the output should be?"

For some cases, this is pretty simple to implement with unsafePerformIO - I've
done that once or twice. Not a sin at all in development.

~~~
clusmore
I hadn't through of doing that, good idea.

------
alphanumeric0
I've been learning Haskell and Idris off and on now for a few years. I have a
few friends who happen to be computer science majors and they tend to be very
dismissive of Haskell, they mostly focus on the performance tweaking of a
Haskell program, which seems to be a 'black art'.

Does anyone know if Idris improves on this aspect of Haskell?

~~~
icen
Idris, unlike Haskell, is strict, which has the general effect of making
Idris' performance a bit more predictable, and a bit more like programming in
other languages.

However, GHC is a phenomenal compiler, and can outperform Idris for many
things; this is natural, as it's seen a lot of interest in terms of producing
performant code.

There are still some gotchas in Idris code. The biggest one that I can think
of is indexing some type with data that doesn't manage to get erased (the
usual type erasure algorithm is pretty aggressive, but it can't remove
everything). Some of the most useful types for programming (as in, proving
theorems about the code) are wonderfully inefficient (as an example, the
inductive definition of natural number is an empty linked list - taking up
plenty of space in pointers, and killing your cache whenever it's accessed -
Idris knows about Nat, but not about other types). Operations on the data,
which might look very efficient, can also end up operating on the indices,
which might not be.

Here's the docs explaining the possible hiccup with erasure:
[http://docs.idris-
lang.org/en/latest/reference/erasure.html](http://docs.idris-
lang.org/en/latest/reference/erasure.html)

~~~
posterboy
>strict

I am eager to point out, how lazy is to call lazy strict.

------
amckinlay
Would be nice to see a dependently-typed strict functional programming
language that didn't require a GC or a C runtime. Are there any plans for this
with Idris?

~~~
david-given
Function programming with no garbage collector is tough. There is a
formalisation for dealing with this, called linear logic, which allows you to
statically determine object lifetimes; but it's, um, a bit awkward. Such as,
every value must be produced once and consumed once, so if you want to look at
a variable, you need to produce a new variable with the same value (which must
be consumed later).

The seminal linearly typed language is Linear Lisp, which is almost
incomprehensible, and also a proof-of-concept which doesn't do anything
useful. Classic paper here:

[http://home.pipeline.com/~hbaker1/LinearLisp.html](http://home.pipeline.com/~hbaker1/LinearLisp.html)

The closest thing to a modern language that uses them exclusively (Rust
doesn't, by the way) is LinearML, which was an experimental toy, now
abandoned. Tutorial here, which may be interesting:

[https://github.com/pikatchu/LinearML/wiki/Tutorial](https://github.com/pikatchu/LinearML/wiki/Tutorial)

I asked about it on StackOverflow a while back, and it collected a bunch of
useful resources, including links to some of the seminal papers:

[http://stackoverflow.com/questions/5065861/programming-
langu...](http://stackoverflow.com/questions/5065861/programming-languages-
based-on-linear-types)

(Still looking for a modern pure linear typed language, by the way.)

~~~
tupshin
In what way is Rust's use of affine lifetimes insufficient to implement
"function programming with no garbage collection"? Genuine question, given my
previous interest :)

[https://twitter.com/tupshin/status/587275945163251713](https://twitter.com/tupshin/status/587275945163251713)

[https://twitter.com/tupshin/status/626164932778819584](https://twitter.com/tupshin/status/626164932778819584)

~~~
david-given
In Rust you're allowed to look at values without consuming them, which pure
linear typing doesn't support (it requires exactly one producer and exactly
one consumer).

Also, in my experience, most Rust programs tend to stash stuff in reference-
counted boxes whenever calculating lifetime gets complex; which is reasonable
enough (C++ does the same thing), but it _is_ basically garbage collection,
and I'd like to find an expressive, functional, non-GCd language which doesn't
require this.

------
weavie
This is pretty exciting. I'm still only about halfway through the book, but I
am really enjoying the language. Learning it has been a real brain melter (in
a good way) so far. Am looking forward to finishing the book.

I do appreciate how you can use dependant types as much or as little as you
like, so in some ways it can actually be considered a simpler and easier to
learn Haskell due to having strict evaluation.

------
hood_syntax
Great to see. Idris is pretty much the final frontier for what I see value in
becoming comfortable with as far as functional programming goes. Hopefully it
gets more momentum moving forward.

~~~
the_duke
The post says "Idris is still primarily a research project".

So I wouldn't count on too much momentum. ;)

~~~
hood_syntax
Well, you're right. But that's where Haskell came from, so I'm not giving up
hope just yet!

------
gcanti
what's the state of the JavaScript backend? I do frontend and I'd really love
to write some code in idris

~~~
adilparvez
Take a look at PureScript [1], it's Haskell-like but strict.

[1]: [http://www.purescript.org/](http://www.purescript.org/)

------
vesak
How are packages handled in Idris? Do they have a cargo/composer/npm analogue?

------
posterboy
Quick question, does design by contract, ie. invariants and so on, warrant
calling dependent typing? I'm currently learning OCL, and Haskell next, hence
the question.

