[prev in list] [next in list] [prev in thread] [next in thread]
List: haskell-cafe
Subject: Re: [Haskell-cafe] Record syntax, reopening a can of worms.
From: Yves_Parès <limestrael () gmail ! com>
Date: 2012-05-27 9:55:50
Message-ID: CACqaG6w+eVda_RO_1jTZEkVhx3SUnQzJTwVsm7iAFFVZZi4Xkg () mail ! gmail ! com
[Download RAW message or body]
[Attachment #2 (multipart/alternative)]
I enclosed a source file that shows the use of a GADT in that case.
2012/5/27 <timothyhobbs@seznam.cz>
> Somehow I don't understand you.
> Could you please fill out your example into a working bit of code?
>
> Thank you,
>
> Timothy
>
>
> ---------- Původnà zpráva ----------
> Od: Yves Parès <limestrael@gmail.com>
>
> Datum: 27. 5. 2012
> Předmět: Re: [Haskell-cafe] Record syntax, reopening a can of worms.
>
> > case myData of
> > myA@A{} -> fooForA's myA
> > myB@B{} -> fooForB's myB
>
> I think this would typecheck if you used GADTs.
> Actually what you'd want is to use the record syntax with GADTs (there are
> to add the extra type safety you want), however both are not compatible.
>
> data ALike
> data BLike
>
> data MyData x where
> A :: Int -> Int -> MyData ALike
> B :: Int -> MyData BLike
>
> a (A x _) = x
> b (A _ x) = x
> c (B x) = x
> -- GHC may require you to write the type signatures for those three
> functions.
> Le 27 mai 2012 10:52, <timothyhobbs@seznam.cz> a écrit :
>
> Your Maybe example is very contrived. The place where I ran into this was
> much less contrived I think.
>
> I have an editor for a visual programming language. That looks like this:
>
> https://github.com/timthelion/gridhaskell-haskarrow/wiki
>
> I'm using a modified version of the Document-View model for application
> design. The commands in the language are defined in the Cell data type:
>
>
> https://github.com/timthelion/gridhaskell-haskarrow/blob/master/Cell.lhs
>
>
> Some Cell types, like Jump, have a long crooked line comming out of them
> called a Path. This line is held in the path :: Maybe Path feild.
>
>
> When I'm drawing the Cell tree, I have a function that extracts these
> Paths.
> https://github.com/timthelion/gridhaskell-haskarrow/blob/master/ArrowDrawing.lhs#L75
>
>
> It used to be, that more types of Cell than just the Jump Cell had a path.
>
>
> As I removed these Paths from the Cell datatype, my line drawing function
> started crashing, whenever it encountered those Cell types. By having
> chosen to use the short hand record selector syntax rather than the long
> hand place value syntax, I caused a runtime error in my code.
>
>
> I could of course have written the same function like this:
>
> > where path_points =
>
>
> > case
> > case cell of
>
>
>
> Types of cells which have paths:
>
> > Cell.Jump _ path -> Just path
>
>
> > _ -> Nothing of
> > Just path -> maybe [] (\p -> [Path.point p]) (Cell.path cell)
>
>
> > Nothing -> []
>
>
> Record selection is a more convenient syntax. It *could* be usefull for
> making more maintainable code(the reason why I choose it). The method I
> have chosen *would* be more maintainable in the case I want to add another
> feild to Jump. In that case I would not have to re-write the path_points
> function. Sadly, due to GHC's unnessesary and complete inability to do
> type safety checking, what should have been a convenient tool, has become
> an unnessecary source of runtime errors!
>
>
> How would I use your syntax in functions that want to pattern match
> against both A and B? I tried this without success:
>
> >data ALike
> >data BLike
>
> >data MyData t = A {a::Int,
> > b::Int} |
> > B {c::Int}
>
> >mkA x y = A x y :: MyData ALike
> >mkB x = B x :: MyData BLike
>
> altRecordSyntaxes.lhs:15:18:
> Couldn't match type `BLike' with `ALike'
> Expected type: MyData ALike
> Actual type: MyData t
> In the first argument of `g', namely `myA'
> In the expression: g myA
>
> >foo :: MyData t -> Int
>
> >foo myA@A{} = g myA
>
> > where
>
> > g :: MyData ALike -> Int
>
> > g myA' = a myA'
>
> >foo myB@B{} = g myB
>
> > where
>
> > g :: MyData BLike -> Int
>
> > g myB' = c myB'
>
> >main :: IO ()
>
> >main = do
>
> > print $ foo $ mkA 1 3
>
>
> This also doesn't work:
>
> >foo :: MyData t -> Int
>
> >foo myData =
>
> > case myData of
>
> > myA@A{} -> fooForA's myA
>
> > myB@B{} -> fooForB's myB
>
> > where
>
> > fooForA's :: MyData ALike -> Int
>
> > fooForA's myA' = a myA'
>
> > fooForB's :: MyData BLike -> Int
>
> > fooForB's myB' = a myB'
>
> >main :: IO ()
>
> >main = do
>
> > print $ foo $ mkA 1 3
>
> My solution looks very clean(except for that nasty looking data
> declaration) and has the same advantages. Really, the current record
> syntax is just flawed :D
>
> >data MyData = A A' | B B'
>
> >data A' = A'{a::Int,
> > b::Int}
> >data B' = B'{c::Int}
>
> >foo :: MyData -> Int
> >foo (A myA) = a myA
> >foo (B myB) = c myB
>
> >main :: IO ()
> >main = print $ foo (A (A' 1 2))
>
> Timothy
>
> ---------- Původnà zpráva ----------
> Od: John Meacham <john@repetae.net>
> Datum: 27. 5. 2012
> Předmět: Re: [Haskell-cafe] Record syntax, reopening a can of worms.
>
> Is it any more ridiculous than
>
> > f x@Nothing {} = fromJust x
> > main = print (f Nothing)
>
> crashing at run time? That is what you are expressing with your first
> one. This issue is completely unrelated to the named field syntax,
> they behave exactly like data types with non-named fields.
>
> However, you can achieve something like what you want with phantom types.
>
> > data ALike
> > data BLike
>
> >data MyData t = A {a::Int,
> > b::Int} |
> > B {c::Int}
>
> > mkA x y = A x y :: MyData ALike
> > mkB x = B x :: MyData BLike
>
> then you can write functions of
> 'MyData ALike' to indicate it will only have 'A' as a constructor
> 'MyData BLike' to indicate it will only have 'B'
> and 'forall t . MyData t' for functions that can take a general MyData
> that can have either.
>
> John
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>
[Attachment #5 (text/html)]
I enclosed a source file that shows the use of a GADT in that case.<br><br><div \
class="gmail_quote">2012/5/27 <span dir="ltr"><<a \
href="mailto:timothyhobbs@seznam.cz" \
target="_blank">timothyhobbs@seznam.cz</a>></span><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex"> <div>Somehow I don't understand you.<br>Could you please \
fill out your example into a working bit of code?<br><br>Thank \
you,<br><p>Timothy</p><p><br></p><p>---------- Původnà zpráva ----------<br>Od: \
Yves Parès <<a href="mailto:limestrael@gmail.com" \
target="_blank">limestrael@gmail.com</a>></p>
<div><div><br>Datum: 27. 5. 2012<br>Předmět: Re: [Haskell-cafe] Record syntax, \
reopening a can of worms.</div></div><p></p><div><div><blockquote><div><p>> case \
myData of<br> > myA@A{} -> fooForA's myA<br>
> myB@B{} -> fooForB's myB</p>
<p>I think this would typecheck if you used GADTs.<br>
Actually what you'd want is to use the record syntax with GADTs (there are to add \
the extra type safety you want), however both are not compatible.</p> <p>data \
ALike<br> data BLike</p>
<p>data MyData x where<br>
A :: Int -> Int -> MyData ALike<br>
B :: Int -> MyData BLike</p>
<p>a (A x _) = x<br>
b (A _ x) = x<br>
c (B x) = x<br>
-- GHC may require you to write the type signatures for those three functions.</p>
<div>Le 27 mai 2012 10:52, <<a href="mailto:timothyhobbs@seznam.cz" \
target="_blank">timothyhobbs@seznam.cz</a>> a écrit :<br><blockquote \
style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <div>Your \
Maybe example is very contrived. The place where I ran into this was much less \
contrived I think.<br><br>I have an editor for a visual programming language. That \
looks like this:<br><br><a \
href="https://github.com/timthelion/gridhaskell-haskarrow/wiki" \
target="_blank">https://github.com/timthelion/gridhaskell-haskarrow/wiki</a><br>
<br><p>I'm using a modified version of the Document-View model for application \
design. The commands in the language are defined in the Cell data \
type:</p><p><br></p><p><a \
href="https://github.com/timthelion/gridhaskell-haskarrow/blob/master/Cell.lhs" \
target="_blank">https://github.com/timthelion/gridhaskell-haskarrow/blob/master/Cell.lhs</a><br>
</p><p><br></p><p>Some Cell types, like Jump, have a long crooked line comming out of \
them called a Path. This line is held in the path :: Maybe Path \
feild.</p><p><br></p><p> When I'm drawing the Cell tree, I have a function that \
extracts these Paths. <a \
href="https://github.com/timthelion/gridhaskell-haskarrow/blob/master/ArrowDrawing.lhs#L75" \
target="_blank">https://github.com/timthelion/gridhaskell-haskarrow/blob/master/ArrowDrawing.lhs#L75</a></p>
<p><br></p><p>It used to be, that more types of Cell than just the Jump Cell had a \
path.</p><p><br></p><p>As I removed these Paths from the Cell datatype, my line \
drawing function started crashing, whenever it encountered those Cell types. By \
having chosen to use the short hand record selector syntax rather than the long hand \
place value syntax, I caused a runtime error in my code.<br>
</p><p><br></p><p>I could of course have written the same function like \
this:<br></p><pre><div style="background-color:transparent"><span>> \
</span><span>where</span> <span>path_points</span> <span>=</span> </div><div \
style="background-color:transparent">
<span>> </span><span>case</span></div><div \
style="background-color:transparent"><span>> </span><span>case</span> \
<span>cell</span> <span>of</span></div><div style="background-color:transparent"><br>
</div><div style="background-color:transparent">Types of cells which have \
paths:</div><div style="background-color:transparent"><br></div><div \
style="background-color:rgb(255,255,204)"><span>> \
</span><span>Cell</span><span>.</span><span>Jump</span><span> _ path</span> \
<span>-></span> Just path<span></span></div>
<div style="background-color:transparent"><span>> \
</span><span>_</span> <span>-></span> <span>Nothing \
of</span></div><div style="background-color:transparent"><span>> \
</span><span>Just path -></span> <span>maybe</span> <span>[]</span> \
<span>(</span><span>\</span><span>p</span> <span>-></span> \
<span>[</span><span>Path</span><span>.</span><span>point</span> \
<span>p</span><span>])</span> \
<span>(</span><span>Cell</span><span>.</span><span>path</span> \
<span>cell</span><span>)</span></div>
<div style="background-color:transparent"><span>> </span><span>Nothing \
-></span> <span>[]</span></div></pre><p><br></p><p>Record selection is a more \
convenient syntax. It *could* be usefull for making more maintainable code(the \
reason why I choose it). The method I have chosen *would* be more maintainable in \
the case I want to add another feild to Jump. In that case I would not have to \
re-write the path_points function. Sadly, due to GHC's unnessesary and complete \
inability to do type safety checking, what should have been a convenient tool, has \
become an unnessecary source of runtime errors!<br>
</p><p><br></p>How would I use your syntax in functions that want to pattern match \
against both A and B? I tried this without success:<br><br>>data \
ALike<br>>data BLike<br><br>>data MyData t = A {a::Int,<br>> b::Int} |<br>
> B {c::Int}<br><br>>mkA x y = A x y :: MyData ALike<br>>mkB x = B x :: \
MyData BLike<br><br>altRecordSyntaxes.lhs:15:18:<br> Couldn't match type \
`BLike' with `ALike'<br> Expected type: MyData ALike<br>
Actual type: MyData t<br> In the first argument of `g', namely \
`myA'<br> In the expression: g myA<br><br>>foo :: MyData t -> \
Int<br><br>>foo myA@A{} = g myA<br><br>> where<br><br>> g :: MyData ALike \
-> Int<br>
<br>> g myA' = a myA'<br><br>>foo myB@B{} = g myB<br><br>> \
where<br><br>> g :: MyData BLike -> Int<br><br>> g myB' = c \
myB'<br><br>>main :: IO ()<br><br>>main = do<br><br>> print $ foo $ \
mkA 1 3<br>
<br><br>This also doesn't work:<br><br>>foo :: MyData t -> \
Int<br><br>>foo myData =<br><br>> case myData of<br><br>> myA@A{} -> \
fooForA's myA<br><br>> myB@B{} -> fooForB's myB<br><br>
> where<br><br>> fooForA's :: MyData ALike -> Int<br><br>> \
fooForA's myA' = a myA'<br><br>> fooForB's :: MyData BLike -> \
Int<br><br>> fooForB's myB' = a myB'<br><br>
>main :: IO ()<br><br>>main = do<br><br>> print $ foo $ mkA 1 3<br><br>My \
solution looks very clean(except for that nasty looking data declaration) and has the \
same advantages. Really, the current record syntax is just flawed :D<br>
<br>>data MyData = A A' | B B'<br><br>>data A' = \
A'{a::Int,<br>> b::Int}<br>>data B' = \
B'{c::Int}<br><br>>foo :: MyData -> Int<br>>foo (A myA) = a \
myA<br>>foo (B myB) = c myB<br>
<br>>main :: IO ()<br>>main = print $ foo (A (A' 1 \
2))<br><br>Timothy<br><br><p>---------- Původnà zpráva ----------<br>Od: John \
Meacham <<a href="mailto:john@repetae.net" \
target="_blank">john@repetae.net</a>><br>
Datum: 27. 5. 2012<br>Předmět: Re: [Haskell-cafe] Record syntax, reopening a can of \
worms.</p><blockquote>Is it any more ridiculous than<br><br>> f x@Nothing {} = \
fromJust x<br>> main = print (f Nothing)<br><br>crashing at run time? That is what \
you are expressing with your first<br>
one. This issue is completely unrelated to the named field syntax,<br>they behave \
exactly like data types with non-named fields.<br><br>However, you can achieve \
something like what you want with phantom types.<br><br>> data ALike<br>
> data BLike<br><br>>data MyData t = A {a::Int,<br>> b::Int} |<br>> B \
{c::Int}<br><br>> mkA x y = A x y :: MyData ALike<br>> mkB x = B x :: MyData \
BLike<br><br>then you can write functions of<br>'MyData ALike' to indicate it \
will only have 'A' as a constructor<br>
'MyData BLike' to indicate it will only have 'B'<br>and 'forall t \
. MyData t' for functions that can take a general MyData<br>that can have \
either.<br><br> John</blockquote></div><br>_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" \
target="_blank">Haskell-Cafe@haskell.org</a><br> <a \
href="http://www.haskell.org/mailman/listinfo/haskell-cafe" \
target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br> \
<br></blockquote></div> </div></blockquote></div></div></div></blockquote></div><br>
--bcaec52be76f235b2f04c1019c9e--
["TestGADTs.hs" (application/octet-stream)]
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic