Haskell: let statement, copy data type to itself with/without modification not working

两盒软妹~` 提交于 2019-12-19 11:09:46

问题


I want to update a record syntax with a change in one field so i did something like:

let rec = rec{field = 1}

But I've noticed that i can't print rec anymore, means the compiler seems to get into an infinite loop when i try. so i have tried doing:

let a = 1 -- prints OK

let a = a -- now i can't print a (also stuck in a loop) 

So i can't do let a = a with any type, but i don't understand why, and how should i resolve this issue.

BTW: while doing:

let b = a {...record changes..}

let a = b

works, but seems redundant.


回答1:


The issue you're running into is that all let and where bindings in Haskell are recursive by default. So when you write

let rec = rec { ... }

it tries to define a circular data type that will loop forever when you try to evaluate it (just like let a = a).

There's no real way around this—it's a tradeoff in the language. It makes recursive functions (and even plain values) easier to write with less noise, but also means you can't easily redefine a a bunch of times in terms of itself.

The only thing you can really do is give your values different names—rec and rec' would be a common way to do this.

To be fair to Haskell, recursive functions and even recursive values come up quite often. Code like

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

can be really nice once you get the hang of it, and not having to explicitly mark this definition as recursive (like you'd have to do in, say, OCaml) is a definite upside.




回答2:


You never need to update a variable : you can always make another variable with the new value. In your case let rec' = rec{field = 1}.

Maybe you worry about performance and the value being unnecessarily copied. That's the compiler's job, not yours : even if you declare 2 variables in your code, the compiler should only make one in memory and update it in place.

Now there are times when the code is so complex that the compiler fails to optimize. You can tell by inspecting the intermediate core language, or even the final assembly. Profile first to know what functions are slow : if it's just an extra Int or Double, you don't care.

If you do find a function that the compiler failed to optimize and that takes too much time, then you can rewrite it to handle the memory yourself. You will then use things like unboxed vectors, IO and ST monad, or even language extensions to access the native machine-level types.




回答3:


First of all, Haskell does not allow "copying" data to itself, which in the normal sense, means the data is mutable. In Haskell you don't have mutable "variable"s, so you will not be able to modify the value a given variable presents.

All you have did, is define a new variable which have the same name of its previous version. But, to do this properly, you have to refer to the old variable, not the newly defined one. So your original definition

let rec = rec { field=1 }

is a recursive definition, the name rec refer to itself. But what you intended to do, is to refer to the rec defined early on.

So this is a name conflict.

Haskell have some machenism to work around this. One is your "temporary renaming".

For the original example this looks like

let rec' = rec
let rec = rec' { field=1 }

This looks like your given solution. But remember this is only available in a command line environment. If you try to use this in a function, you may have to write

let rec' = rec in let rec = rec' { field=1 } in ...

Here is another workaround, which might be useful when rec is belong to another module (say "MyModule"):

let rec = MyModule.rec { field=1 }


来源:https://stackoverflow.com/questions/39117524/haskell-let-statement-copy-data-type-to-itself-with-without-modification-not-w

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!