Create simple functions with dependent types - idris

I am learning from the official documentation. I have tried to modify the first example:
isSingleton : Bool -> Type
isSingleton True = Nat
isSingleton False = List Nat
mkSingle : (x : Bool) -> isSingleton x
mkSingle True = 0
mkSingle False = []
Here are my tries:
compute_type : Integer -> Type
compute_type 1 = Nat
compute_type 2 = String
--foo : (x : Integer) -> compute_type x
-- foo 1 = Z
-- foo 2 = ?one --unwords ["A", "B", "C"]
Error:
{-
first_class_type.idr:7:13:
|
7 | foo 1 = Z
| ^
When checking right hand side of foo with expected type
compute_type 1
Type mismatch between
Nat (Type of 0)
and
compute_type 1 (Expected type)
-}
ct2 : String -> Type
ct2 "Integer" = Integer
ct2 "String" = String
foo2 : (s : String) -> ct2 s
-- foo2 "Integer" = 42
Error:
{-
|
28 | foo2 "Integer" = 42
| ~~
When checking right hand side of foo2 with expected type
ct2 "Integer"
ct2 "Integer" is not a numeric type
-}
ct3: Bool -> Bool -> Type
ct3 True True = Nat
ct3 False False = String
foo3: (a: Bool) -> (b: Bool) -> (ct3 a b)
-- foo3 True True = Z
-- foo3 False False = "Stringggg"
Error:
{-
first_class_type.idr:44:18:
|
44 | foo3 True True = Z
| ^
When checking right hand side of foo3 with expected typ
ct3 True True
Type mismatch between
Nat (Type of 0)
and
ct3 True True (Expected type)
Holes: Main.foo3, Main.foo2
-}
ct4: (b: String) -> Type
ct4 "Integer" = Integer
ct4 "String" = String
foo4: (s: String) -> ct4 s -> Integer
-- foo4 "Integer" x = x
-- foo4 "String" ss = 987
Error:
{-
|
67 | foo4 "Integer" x = x
| ^
When checking right hand side of foo4 with expected type
Integer
Type mismatch between
ct4 "Integer" (Type of x)
and
Integer (Expected type)
-}
I have no idea why my functions do not returns types. They look similar to Idris codes but they do not work.

Your type functions are not total. You can check this with :total foo or specifying, that the function should be total:
%default total
-- or
total foo : Integer -> Type
Only total functions are get resolved in the type checker, otherwise it may or may not run forever. If you want to stick to Integer and String, to make your functions total, you can just add a default case:
compute_type : Integer -> Type
compute_type 1 = Nat
compute_type _ = String
foo : compute_type 1
foo = Z

Related

Pattern-match (destructure) in equality proof

data T = A String | B String
p : ((A s) = (A s')) -> (s = s')
If I have (A s) = (A s'), how do I obtain s = s'?
P.S. I'm new to Idris. Feel free to edit my question for code style or to add pertinent keywords.
Pattern match on Refl:
data T = A String | B String
p : ((A s) = (A s')) -> (s = s')
p Refl = Refl

Problem with dependent types function in Idris

I have just started reading a book "Type-driven development" and tried my simple example with dependent types. It should return a string for negative numbers and Integer for the positive ones.
I started with 2 holes:
StringOrInt : Bool -> Type
StringOrInt b =
case b of
True => Integer
False => String
getStringOrInt : (x : Integer) -> StringOrInt (x > 0)
getStringOrInt x =
case x > 0 of
True => ?x
False => ?s
If I take a look at holes definition it looks very complicated and not helpful at all:
x : case with block in Prelude.Interfaces.Prelude.Interfaces.Integer implementation of Prelude.Interfaces.Ord, method > (ifThenElse (intToBool (prim__eqBigInt x 0))
(Delay EQ)
(Delay (ifThenElse (intToBool (prim__sltBigInt x
0))
(Delay LT)
(Delay GT))))
x
0 of
True => Integer
False => String
So how to write this function?
Use with rather than case to leverage dependent pattern matching and have the type checker substitute the appropriate Boolean for x > 0 in the result type for each alternative:
StringOrInt : Bool -> Type
StringOrInt True = Integer
StringOrInt False = String
getStringOrInt : (x : Integer) -> StringOrInt (x > 0)
getStringOrInt x with (x > 0)
getStringOrInt x | True = x
getStringOrInt x | False = "<= 0"

Type mismatch involving three types that must be identical

This compiles:
data ThreeEq : a -> b -> c -> Type where
Same3 : (x : a) -> ThreeEq x x x
allSameS : (x, y, z : Nat) -> ThreeEq x y z -> ThreeEq (S x) (S y) (S z)
allSameS k k k (Same3 k) = Same3 (S k)
But with one small change to Same3, it no longer compiles. Can anyone explain why?
data ThreeEq : a -> b -> c -> Type where
Same3 : x -> ThreeEq x x x
allSameS : (x, y, z : Nat) -> ThreeEq x y z -> ThreeEq (S x) (S y) (S z)
allSameS k k k (Same3 k) = Same3 (S k)
Here's the error message:
- + Errors (1)
`-- Amy2.idr line 5 col 0:
When checking left hand side of allSameS:
When checking an application of Main.allSameS:
Type mismatch between
ThreeEq x x x (Type of Same3 _)
and
ThreeEq k y z (Expected type)
Specifically:
Type mismatch between
Type
and
Nat
Here is the difference
data ThreeEq : a -> b -> c -> Type where
Same3 : (x : a) -> ThreeEq x x x
^ ^
| |
| Type
Value
Here, Same3 Z builds a value of type Three Z Z Z.
data ThreeEq : a -> b -> c -> Type where
Same3 : x -> ThreeEq x x x
^
|
Type
And now, Same3 Z builds a value of type Three Nat Nat Nat.

Idris determining result vector length

In Idris, if I want to remove an element based on predicate, there is filter, dropWhile, takeWhile. However, all these functions return a dependent pair (n : Nat ** Vect n elem).
Is there any function that return back as a Vect type?
For what I could think of:
Convert a dependent pair to Vect
Implement a type that indicate the length vector after transformation (thought I have no idea how), like Here, There
For above ideas, it seems quite cumbersome for 1 (convert every result) or 2 (design each of the type to indicate the result vector length).
Are there any better ways to achieve such behaviour?
dropElem : String -> Vect n String -> Vect ?resultLen String
Maybe this is what you are searching for?
import Data.Vect
count: (ty -> Bool) -> Vect n ty -> Nat
count f [] = 0
count f (x::xs) with (f x)
| False = count f xs
| True = 1 + count f xs
%hint
countLemma: {v: Vect n ty} -> count f v `LTE` n
countLemma {v=[]} = LTEZero
countLemma {v=x::xs} {f} with (f x)
| False = lteSuccRight countLemma
| True = LTESucc countLemma
filter: (f: ty -> Bool) -> (v: Vect n ty) -> Vect (count f v) ty
filter f [] = []
filter f (x::xs) with (f x)
| False = filter f xs
| True = x::filter f xs
Then you con do this:
dropElem: (s: String) -> (v: Vect n String) -> Vect (count ((/=) s) v) String
dropElem s = filter ((/=) s)
You can even reuse the existing filter implementation:
count: (ty -> Bool) -> Vect n ty -> Nat
count f v = fst $ filter f v
filter: (f: ty -> Bool) -> (v: Vect n ty) -> Vect (count f v) ty
filter f v = snd $ filter f v

Idris proof of less than

I'm very new to Idris (and dependent types). I was trying to do write a program to check if a string is a palindrome of not. To do that, I decided to compute the length of the string, and compute
q,r = (strlen `div` 2, strlen `mod` 2)
and then split the string as follows:
lhalf,rhalf = (substr 0 (q+r) str, substr (q-r) (q+r) str)
This takes care of both odd and even length strings. The problem is that Idris needs a proof that r < q since both q and r are Nat.
My question is: How do I express the fact that r
Here's the full sample of my code:
module Main
isPalindrome : (str : String) -> String
isPalindrome str =
let split = half_half str
in show ((fst split) == reverse (snd split))
where
strlen : Nat
strlen = length str
divMod : Nat -> Nat -> (Nat,Nat)
divMod x y = (x `div` y, x `mod` y)
half_half : String -> (String, String)
half_half "" = ("","")
half_half x = let
(q,r) = divMod strlen 2
in
(substr 0 (q+r) x,
substr (q-r) (q+r) x)
main : IO ()
main = repl "> " isPalindrome
You can't proof that r ≤ q because it's not true. For example, given the string "a" you have strlen = 1 and therefore q = 0 and r = 1. In this example r ≤ q is clearly false.
Note that you can implement isPalindrome simply by
isPalindrome: String -> Bool
isPalindrome str = str == reverse str