Skip to content

Instantly share code, notes, and snippets.

@ivan-kleshnin
Last active August 14, 2017 10:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ivan-kleshnin/5c05be5a1f671fd77c5b16f4d6452f63 to your computer and use it in GitHub Desktop.
Save ivan-kleshnin/5c05be5a1f671fd77c5b16f4d6452f63 to your computer and use it in GitHub Desktop.
Idris: first impression

Idris: first impression

Language

Likes

Dependent types

The idea and approach is brilliant. I hope it's the next big thing in programming.

Eager evaluation

I'm quite sure Haskell didn't get mainstream because of it's non-strict evaluation. It's just too alien. Everything else: syntax, types, FP, typeclasses, monads... are EASY in comparison. Haskell heritage is useful as people can copy-paste a big set of tested solutions to their Lazy libraries. But for me it's "Opt-in laziness > Opt-out laziness" from now on.

Type operator syntax

Swap between : and :: suits well for Idris.

List type syntax

List String instead of [String] (PureScript did that too!).

Polymorphic literals

This is insanely good.

Idris> the (List _) ["Hello", "There"]
["Hello", "There"] : List String
Idris> the (Vect _ _) ["Hello", "There"]
["Hello", "There"] : Vect 2 String

Dislikes

Implicit import all

Haskell-like abomination:

import SomeModule -- @_@

I caught myself to find (real) Haskell code plainly undreadable way too often. I just couldn't trace functions to their host packages. So basic and so annoying.

Named arguments

Idris> :doc List
...
(::) : (x : elem) -> (xs : List elem) -> List elem
-- instead of a MORE readable
(::) : a -> List a -> List a

I believe that x and xs add nothing to the picture except a visual noise. I hate TypeScript for it's Java-like type syntax with ugly and unclear type signatures which you need to decipher every time you see them. I'm afraid Idris is leaning to the same direction.

Tuple type syntax

It's still (String, Bool) instead of Tuple String Bool. Seems not consistent. PureScript did that better I guess.

Error messages

Almost all of them are not helpful. It's like Haskell telling you to enable some magical extension when you just miss a comma...

Library names

Something about List (singular) vs Strings (plural) bugs me, and you see those two together a lot.

Books and Docs

TDD with Idris – awesome book. More readable than all Haskell books I tried(!)

Editors / IDE

Used Atom. Relied only on syntax highlighting. Nothing to say for now.

Community

Community is super small. Don't expect to find help as IRC is empty and mailing list is silent so to say.

Quirks

Quirk 1

Idris> :let square : Double -> Double
Idris> :let square x = x * x
When checking an application of function Prelude.Interfaces.*:
        No such variable x                                          ??? @_@
Idris> :let square : Double -> Double ; square x = x * x
(input):1:13:square already defined                                 ??? @_@
(input):1:13:square is already defined                              ??? @_@
Idris> square 2
square 2.0 : Double                                                 ??? @_@

So how to declare multi-line function in REPL? I've found no such examples at docs or GitHub :(

Quirk 2

Idris> :t \x => x + x
\x => x + x : Integer -> Integer ??? @_@ why not Num a => a -> a
Idris> (\x => x + x) 2.0
4.0 : Double                     ??? @_@ so Integer or Double 

Quirk 3

Works:

wordCount : String -> Nat
wordCount str = length (words str)

average : (str : String) -> Double
average str = let numWords = wordCount str
                  totalLength = sum (allLengths (words str)) in
                  cast totalLength / cast numWords
  where
    allLengths : List String -> List Nat
    allLengths strs = map length strs

Fails at #1:

wordCount : String -> Nat
wordCount str = length (words str)

average : (str : String) -> Double
average str = let numWords = wordCount str
                  totalLength = sum (map length (words str)) in -- #1
                  cast totalLength / cast numWords

with the message

When checking right hand side of average with expected type
             Double
     
Can't disambiguate since no name has a suitable type: 
             Prelude.List.length, Prelude.Strings.length

the solution is to add namespace Strings.length to the map length call.

Another example of the same(?) name disambiguation weirdness:

Works:

topTen : Ord a => List a -> List a
topTen xs = take 10 $ reverse $ sort xs

Fails:

topTen : Ord a => List a -> List a
topTen xs = (take 10 . reverse . sort) xs

with the message: Can't disambiguate name: Prelude.List.take, Prelude.Stream.take

Works again:

topTen : Ord a => List a -> List a
topTen xs = (List.take 10 . reverse . sort) xs

I hit several of those in total. So I wonder:

  1. Should I just always use namespaces to avoid such traps?
  2. Why support function overload at all. It just fails too often imo...

Quirk 4

Works:

module Main

palindrome : String -> Bool
palindrome s = s1 == reverse (toLower s)
  where s1 = toLower s

Fails at #1:

module Main

palindrome : String -> Bool 
palindrome s = s1 == s2 -- #1
  where s1 = toLower s
        s2 = reverse (toLower s)

with the message Can't find implementation for Eq ty. From the docs I understood that where is for functions and let is for variables (not sure a requirement or a convention) but why one variable works and two – don't?! @_@

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment