Problem with naming record fields for List data type - liquid-haskell

For the sake of demonstration, I have two nearly-identical files: ListSuccess.hs and ListFailure.hs:
-- File: ListSuccess.hs
module ListSuccess where
import Prelude hiding ( head
, tail
)
{-#
data List a = Nil | Cons { lh :: a , lt :: List a }
#-}
data List a = Nil |Cons { lh :: a , lt :: List a }
-- File: ListFailure.hs
module ListFailure where
import Prelude hiding ( head
, tail
)
{-#
data List a = Nil | Cons { head :: a , tail :: List a }
#-}
data List a = Nil | Cons { head :: a , tail :: List a }
The only difference between these files is that ListSuccess names the fields of Cons as lh and lt, and ListFailure names the fields of Cons as head and tail.
Compiling with liquid, ListSuccess.hs compiles successfully, however ListFailure fails to compile, yielding this error:
10 | data List a = Nil | Cons { head :: a , tail :: List a }
^^^^^
ListFailure.head :: forall a .
lq$recSel:(ListFailure.List a) -> {VV : a | VV == head lq$recSel}
Sort Error in Refinement: {VV : a##xo | VV == head lq$recSel}
Cannot unify fix$36$$91$$93$ with ListFailure.List in expression: head lq$recSel
/Users/henry/Documents/Prototypes/liquidhaskell/list-fields-bug/ListFailure.hs:12:21-55: Error: Illegal type specification for `ListFailure.Cons`
12 | data List a = Nil | Cons { head :: a , tail :: List a }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ListFailure.Cons :: forall a .
head:a -> tail:(ListFailure.List a) -> {VV : (ListFailure.List a) | tail VV == tail
&& head VV == head}
Sort Error in Refinement: {VV : (ListFailure.List a##agi) | (tail VV == tail##ListFailure.Cons
&& head VV == head##ListFailure.Cons)}
Cannot unify fix$36$$91$$93$ with ListFailure.List in expression: tail VV
As far as I can tell, using head and tail as the field names should not be an issue, especially because I imported prelude hiding those names. The same error occurs even when I use import qualified Prelude and similar variants.
Is this a bug, or is there something that I'm missing here?
Configuration:
LiquidHaskell Version 0.8.6.0.

Related

How do I use (#) operator in Haskell as I get parse error on input?

I am new to Haskell and I am trying to calculate the maximum segment sum,
(#) :: Int -> Int -> Int
x # y = 0 `max` (x + y)
mss2 :: [Int] -> Int
mss2 = maximum . scanr (#) 0
The error is
No Modules Loaded for (#)
I found this snippet in Richard Bird's text.
What am I missing here?
Are there other ways to declare/overload the operators, is my approach wrong?
It appears that in the context of that book, (#) is being used as a stand-in for some binary operator such as (+) or (<>), even though this is not actually legal Haskell syntax†.
For questions about Haskell syntax, it’s helpful to consult the Haskell 2010 Report.
In Ch. 2 Lexical Structure, under §2.2 Lexical Program Structure, you can find # in the grammar of symbols that may appear in an operator name:
symbol → ascSymbol | uniSymbol⟨special | _ | " | '⟩
ascSymbol → ! | # | $ | % | & | ⋆ | + | . | / | < | = | > | ? | #
| \ | ^ | | | - | ~ | :
And §2.4 Lexical Structure: Identifiers and Operators defines valid operator names to include such symbols:
varsym → ( symbol⟨:⟩ {symbol} )⟨reservedop | dashes⟩
consym → ( : {symbol} )⟨reservedop⟩
However, the subscript in angle brackets denotes a “difference” or exclusion, so this disallows a list of reserved identifiers. Under the production reservedop you can find that # appears in that list:
reservedop → .. | : | :: | = | \ | | | <- | -> | # | ~ | =>
The reason is that the # symbol denotes an “as” pattern, described in §3.17.2.8 Informal Semantics of Pattern Matching:
Matching an as-pattern var#apat against a value v is the result of matching apat against v, augmented with the binding of var to v.
As patterns are very useful for controlling the sharing of values and making certain definitions more concise, e.g.:
-- | Merge two sorted lists.
merge :: (Ord a) => [a] -> [a] -> [a]
-- ‘as0’ & ‘bs0’ denote the original input lists.
-- ‘as’ & ‘bs’ denote their tails.
merge as0#(a : as) bs0#(b : bs) = case compare a b of
-- ‘as0’ passes along the same list cell;
-- repeating ‘a : as’ would allocate a /new/ cell.
GT -> b : merge as0 bs
_ -> a : merge as bs0
merge [] bs0 = bs0
merge as0 [] = as0
Therefore, the definition:
x # y = 0 `max` (x + y)
Or more conventionally written x#y = …, is equivalent to defining two variables referring to the same value, which furthermore is defined recursively:
x = 0 `max` (x + y)
y = x
Without the type signature Int -> Int -> Int, this definition would be accepted, defining x, y :: (Ord a, Num a) => a, but attempting to evaluate either variable would produce an infinite loop, since this is “unproductive” recursion.
The solution is to use a non-reserved symbol as your operator name instead, such as <#> or +..
† I can’t find a citation for this, but it’s possible that GHC used to accept this syntax, even though it was also disallowed by the Haskell 98 Report which was current at the time the first edition of this book came out, and that this example code just wasn’t updated for the second edition.

Can't prove unique refinement type for filter function

I am following the LH tutorial and am stuck at the excersise to refine the type of the filter function in a way that, if called with a list with unique elements, the output is also a unique list with unique elements.
This is the code I am working with:
import Data.Set hiding (insert, partition, filter, split, elems)
{-# measure elts #-}
elts :: (Ord a) => [a] -> Set a
elts [] = empty
elts (x:xs) = singleton x `union` elts xs
{-# measure unique #-}
unique :: (Ord a) => [a] -> Bool
unique [] = True
unique (x:xs) = unique xs && not (member x (elts xs))
{-# filter' :: (a -> Bool) -> xs:[a] -> { l:[a] | unique xs => unique l } #-}
filter' _ [] = []
filter' f (x:xs)
| f x = x : xs'
| otherwise = xs'
where
xs' = filter' f xs
however, when let LH prove it the following error is thrown by LH:
filter.hs:16:17-23: Error: Liquid Type Mismatch
16 | | f x = x : xs'
^^^^^^^
Inferred type
VV : {v : [a] | tail v == xs'
&& head v == x
&& listElts v == Set_cup (Set_sng x) (listElts xs')
&& len v == 1 + len xs'
&& Main.elts v == Set_cup (Set_sng x) (Main.elts xs')
&& (Main.unique v <=> Main.unique xs'
&& not (Set_mem x (Main.elts xs')))
&& len v >= 0}
not a subtype of Required type
VV : {VV : [a] | Main.unique ?a => Main.unique VV}
In Context
xs : {v : [a] | len v >= 0}
xs' : {v : [a] | (Main.unique xs => Main.unique v)
&& len v >= 0}
x : a
?a : {?a : [a] | len ?a >= 0}
I have already tried to specify it differently, using an if in the refinement and by using different refinement types, but none of it seems to work...
can you please point me in the right direction? I am still having a hard time understanding the error messages. As I understand it, the inferred type contains the information that it is uniqe if xs' is unique, so in my opinion, this should be a subtype of the required one.
sorry for the delay, I just saw this! (I tend to monitor the slack channel more closely.) The error message basically says that LH cannot prove that the output list x:xs' will indeed be unique. Specifically, LH has no way to know that x is not already an element of xs'.
Now, why is x not an element of xs'? Because
(1) x is not an element of xs AND
(2) xs' is a subset of the values of xs
LH knows the first property if the input list is unique.
But it does not know the second. So if you add that to the output
of filter that would help.
[This is an excellent question by the way; I will update the tutorial with a hint]

Convert a string to a list of "grades"

I want to make a function that takes in a string of multiple "grades" of varying length and convert it to a list of grades.
Grade is just a data structure that looks like this (just an arbitrary grading system):
data Grade = A+ | A | A- | B+ | B | B- | P | F
deriving (Show, Eq)
As you can see, the grades have varying length. If they had length 1 or consistent length, this would have been much easier.
Here is the function that I want to make:
This is what the string input looks like "PA+FABA+B-A"
stringToGrade :: String -> Grade
stringToGrade stringGrade
| stringGrade == "A+" = A+
| stringGrade == "A" = A
-- and so on
extractGrades :: String -> [Grade]
extractGrades stringGrades = case stringGrades of
[] -> []
x:y:ys
| x == "A" && y == "+" -> [stringToGrade (x : y)] : extractGrades ys
| x == "A" -> [stringToGrade x] : extractGrades y:ys
-- and so on
As you can see, this is not going anywhere.
Is there an elegant and easy way I cam do this instead of had coding everything?
We can apply pattern matching so to match a string prefix. Here's an example:
foo :: String -> [Int]
foo [] = []
foo ('h':'e':'l':'l':'o':rest) = 1 : foo rest
foo ('b':'o':'b':rest) = 2 : foo rest
foo ('b':rest) = 3 : foo rest
foo _ = error "foo: invalid input syntax"
Sample usage:
foo "hellobbobbobhello" ==> [1,3,2,2,1]
You can split the string into tokens using combination of split functions.
split (keepDelimsR $ oneOf "+-") "PA+FABA+B-A"
will create this form, where the suffixes are attached.
["PA+","FABA+","B-","A"]
Now, you can split this further with a custom splitter
splitInit [] = []
splitInit [x] = [[x]]
splitInit [x,y] = [[x,y]]
splitInit (x:xs) = [x] : splitInit xs
a combination will give you
concatMap splitInit $ split (keepDelimsR $ oneOf "+-") "PA+FABA+B-A"
["P","A+","F","A","B","A+","B-","A"]
where you can map through your constructors

why not a case with predicate guards in addition to pattern guards?

why not a case with predicate guards in addition to pattern guards?
{-# LANGUAGE MultiWayIf, LambdaCase #-}
module Main where
import System.Info (os)
import Control.Applicative ((<$>))
import Data.Char (toLower)
import Data.List (isPrefixOf)
main :: IO ()
main = print . ($ toLower <$> os) $ \x -> if
| "mingw" `isPrefixOf` x -> "windows"
| "darwin" == x -> "mac"
| otherwise -> "linux"
would be prettier as:
main = print $ case toLower <$> os of
x | "mingw" `isPrefixOf` x -> "windows"
| "darwin" == x -> "mac"
| otherwise -> "linux"
or even:
main = print $ case toLower <$> os of
| ("mingw" `isPrefixOf`) -> "windows"
| ("darwin" ==) -> "mac"
| otherwise -> "linux" -- when pattern absent: otherwise = const True
Your first proposal is valid syntax, so just use it:
main = print $ case toLower <$> os of
x | "mingw" `isPrefixOf` x -> "windows"
| "darwin" == x -> "mac"
| otherwise -> "linux"
Edit: I thought you were aiming for a point-free case at all costs. Your pointful proposal is indeed correct syntax, as András Kovács points out.
Here is a pointless-style match:
{-# LANGUAGE ViewPatterns #-}
main = print $ case toLower <$> os of
(("mingw" `isPrefixOf`) -> True) -> "windows"
(("darwin" ==) -> True) -> "mac"
_ -> "linux"
or even, without view patterns:
match :: a -> [(a -> Bool, b)] -> b
match x ((f,y):rest) | f x = y
| otherwise = match x rest
match _ [] = error "Non exhaustive predicates"
main = print $ match (toLower <$> os)
[(("mingw" `isPrefixOf`) , "windows")
,(("darwin"==) , "mac")
,((const True) , "linux")]

Library for tree output of data for analysis

For convenient analysis of data I'd like to use a library which for the following code:
data SomeType = A [String] Int | B | C Int deriving (Eq, Ord, Show)
main = do
let theData = A ["a", "b", "c"] 9 : C 3 : B : []
putStr $ treeString theData -- `treeString` is the implied library function
would produce an output similar to the following:
- A:
| - - a
| | - b
| | - c
| - 9
- C:
| - 3
- B
Is there such a library? Or maybe a better approach to such a problem?
Data.Tree has drawTree and drawForest functions with similar formatting, so you can write a function to convert your data structure to a Tree String and then use drawTree.
import Data.Tree
data SomeType = A [String] Int | B | C Int deriving (Eq, Ord, Show)
toTree :: SomeType -> Tree String
toTree (A xs n) = Node "A" [Node "*" (map (flip Node []) xs), Node (show n) []]
toTree B = Node "B" []
toTree (C n) = Node "C" [Node (show n) []]
main = do
let theData = A ["a", "b", "c"] 9 : C 3 : B : []
putStr $ drawTree (Node "*" (map toTree theData))
Output:
*
|
+- A
| |
| +- *
| | |
| | +- a
| | |
| | +- b
| | |
| | `- c
| |
| `- 9
|
+- C
| |
| `- 3
|
`- B
Adding to hammar's answer. Here's how one can do a generic conversion to Data.Tree:
import Data.Tree
import Data.Generics
import Control.Applicative
dataTree = fix . genericTree
where
genericTree :: Data a => a -> Tree String
genericTree = dflt `extQ` string
where
string x = Node x []
dflt a = Node (showConstr (toConstr a)) (gmapQ genericTree a)
fix (Node name forest)
| name == "(:)"
, a : b : [] <- forest
= Node "*" $ (fix a) : (subForest $ fix b)
| otherwise = Node name $ fix <$> forest
But for this to work on one's data types, they must have an instance of Data, which can easily be achieved by adding a {-# LANGUAGE DeriveDataTypeable #-} pragma and making the type derive from Typeable and Data like so:
data SomeType = A [String] Int | B | C Int | D [[String]]
deriving (Typeable, Data)

Resources